From 8afd9a5e1d2cb7cf5371cffff30a6216b8b80b28 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Jun 2015 11:04:52 -0700 Subject: [PATCH 01/24] add EntityItem::_simulatorPriority as uint8_t --- libraries/entities/src/EntityItem.cpp | 46 ++++++++++++++++++- libraries/entities/src/EntityItem.h | 8 +++- .../entities/src/EntityItemProperties.cpp | 7 +++ libraries/entities/src/EntityItemProperties.h | 2 + libraries/entities/src/EntityPropertyFlags.h | 1 + libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 1 + 7 files changed, 64 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 74b7a36504..289cc888a9 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -64,6 +64,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _collisionsWillMove(ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE), _locked(ENTITY_ITEM_DEFAULT_LOCKED), _userData(ENTITY_ITEM_DEFAULT_USER_DATA), + _simulatorPriority(0), _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), _simulatorIDChangedTime(0), _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), @@ -249,6 +250,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); + APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_PRIORITY, getSimulatorPriority()); APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, getSimulatorID()); APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID()); APPEND_ENTITY_PROPERTY(PROP_NAME, getName()); @@ -569,7 +571,47 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); - if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { + if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATOR_PRIORITY) { + uint8_t priority = 0; + if (propertyFlags.getHasProperty(PROP_SIMULATOR_PRIORITY)) { + int bytes = OctreePacketData::unpackDataFromBytes(dataAt, priority); + dataAt += bytes; + bytesRead += bytes; + } + + QUuid id; + if (propertyFlags.getHasProperty(PROP_SIMULATOR_ID)) { + int bytes = OctreePacketData::unpackDataFromBytes(dataAt, id); + dataAt += bytes; + bytesRead += bytes; + } + + if (_simulatorID != id) { + // ownership has changed + auto nodeList = DependencyManager::get(); + if (_simulatorID == nodeList->getSessionUUID()) { + // we think we're the owner but entityServer says otherwise + // we only relenquish ownership if the incoming priority is greater than ours + if (priority > _simulatorPriority) { + // we're losing simulation ownership + _simulatorID = id; + _simulatorPriority = priority; + _simulatorIDChangedTime = usecTimestampNow(); + } + } else { + _simulatorID = id; + _simulatorPriority = priority; + _simulatorIDChangedTime = usecTimestampNow(); + } + } else if (priority != _simulatorPriority) { + // This should be an uncommon event: priority is changing but simulatorID is not. + // But we only accept this change if we are NOT the simulator owner. + auto nodeList = DependencyManager::get(); + if (_simulatorID != nodeList->getSessionUUID()) { + _simulatorPriority = priority; + } + } + } else if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { // we always accept the server's notion of simulatorID, so we fake overwriteLocalData as true // before we try to READ_ENTITY_PROPERTY it bool temp = overwriteLocalData; @@ -918,6 +960,7 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulatorID, getSimulatorID); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulatorPriority, getSimulatorPriority); COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName); COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); @@ -968,6 +1011,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorPriority, setSimulatorPriority); SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorID, updateSimulatorID); // non-simulation properties below diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 3ce3a8e269..135ac78617 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -60,6 +60,8 @@ const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; const float ACTIVATION_GRAVITY_DELTA = 0.1f; const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; +const uint8_t MIN_SIMULATOR_PRIORITY = 1; +const uint8_t MAX_SIMULATOR_PRIORITY = 0xff; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; @@ -317,7 +319,10 @@ public: const QString& getUserData() const { return _userData; } void setUserData(const QString& value) { _userData = value; } - + + void setSimulatorPriority(uint8_t priority) { _simulatorPriority = priority; } + uint8_t getSimulatorPriority() const { return _simulatorPriority; } + QUuid getSimulatorID() const { return _simulatorID; } void setSimulatorID(const QUuid& value); void updateSimulatorID(const QUuid& value); @@ -426,6 +431,7 @@ protected: bool _collisionsWillMove; bool _locked; QString _userData; + uint8_t _simulatorPriority; QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity quint64 _simulatorIDChangedTime; // when was _simulatorID last updated? QString _marketplaceID; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f755cd49fb..b33889189f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -73,6 +73,7 @@ CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED), CONSTRUCT_PROPERTY(textures, ""), CONSTRUCT_PROPERTY(animationSettings, ""), CONSTRUCT_PROPERTY(userData, ENTITY_ITEM_DEFAULT_USER_DATA), +CONSTRUCT_PROPERTY(simulatorPriority, 0), CONSTRUCT_PROPERTY(simulatorID, ENTITY_ITEM_DEFAULT_SIMULATOR_ID), CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT), CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT), @@ -324,6 +325,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked); CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures); CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData); + CHECK_PROPERTY_CHANGE(PROP_SIMULATOR_PRIORITY, simulatorPriority); CHECK_PROPERTY_CHANGE(PROP_SIMULATOR_ID, simulatorID); CHECK_PROPERTY_CHANGE(PROP_TEXT, text); CHECK_PROPERTY_CHANGE(PROP_LINE_HEIGHT, lineHeight); @@ -419,6 +421,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(locked); COPY_PROPERTY_TO_QSCRIPTVALUE(textures); COPY_PROPERTY_TO_QSCRIPTVALUE(userData); + COPY_PROPERTY_TO_QSCRIPTVALUE(simulatorPriority); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(simulatorID, getSimulatorIDAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(text); COPY_PROPERTY_TO_QSCRIPTVALUE(lineHeight); @@ -570,6 +573,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec return result; }); + COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorPriority, float, setSimulatorPriority); COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); } @@ -727,6 +731,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, properties.getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); + APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_PRIORITY, properties.getSimulatorPriority()); APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, properties.getSimulatorID()); APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); @@ -982,6 +987,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATOR_PRIORITY, uint8_t, setSimulatorPriority); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATOR_ID, QUuid, setSimulatorID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription); @@ -1110,6 +1116,7 @@ void EntityItemProperties::markAllChanged() { _frictionChanged = true; _lifetimeChanged = true; _userDataChanged = true; + _simulatorPriorityChanged = true; _simulatorIDChanged = true; _scriptChanged = true; _scriptTimestampChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index fdf01c4761..6f2aca8d92 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -120,6 +120,7 @@ public: DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString); DEFINE_PROPERTY_REF_WITH_SETTER_AND_GETTER(PROP_ANIMATION_SETTINGS, AnimationSettings, animationSettings, QString); DEFINE_PROPERTY_REF(PROP_USER_DATA, UserData, userData, QString); + DEFINE_PROPERTY(PROP_SIMULATOR_PRIORITY, SimulatorPriority, simulatorPriority, uint8_t); DEFINE_PROPERTY_REF(PROP_SIMULATOR_ID, SimulatorID, simulatorID, QUuid); DEFINE_PROPERTY_REF(PROP_TEXT, Text, text, QString); DEFINE_PROPERTY(PROP_LINE_HEIGHT, LineHeight, lineHeight, float); @@ -284,6 +285,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Locked, locked, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Textures, textures, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, UserData, userData, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulatorPriority, simulatorPriority, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulatorID, simulatorID, QUuid()); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Text, text, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LineHeight, lineHeight, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index e83a69227f..08569adaf4 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -121,6 +121,7 @@ enum EntityPropertyList { // used by hyperlinks PROP_HREF, PROP_DESCRIPTION, + PROP_SIMULATOR_PRIORITY, PROP_FACE_CAMERA, PROP_SCRIPT_TIMESTAMP, diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 5fe9bbbb99..1c14c3dbde 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -73,7 +73,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketTypeEntityAdd: case PacketTypeEntityEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX; + return VERSION_ENTITIES_HAVE_SIMULATOR_PRIORITY; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 789675ec00..52a45ea913 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -186,5 +186,6 @@ const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29; const PacketVersion VERSION_ENTITIES_FACE_CAMERA = 30; const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 31; const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32; +const PacketVersion VERSION_ENTITIES_HAVE_SIMULATOR_PRIORITY = 33; #endif // hifi_PacketHeaders_h From 443c7d9c70df2cb6d525b5bf9dad56c787ac6153 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Jun 2015 11:26:17 -0700 Subject: [PATCH 02/24] allow equal priority to take simulation ownership --- libraries/entities/src/EntityItem.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 289cc888a9..37164bd6f6 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -563,7 +563,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); - //READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); @@ -572,6 +571,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATOR_PRIORITY) { + // NOTE: the server is authoritative for changes to _simulatorID so we always unpack this data, + // even when we would otherwise ignore the rest of the packet. That said, we assert the priority + // rules that we expect the server to be using, so it is possible that we'll sometimes ignore + // the incoming _simulatorID data (e.g. we might know something that the server does not... yet). + uint8_t priority = 0; if (propertyFlags.getHasProperty(PROP_SIMULATOR_PRIORITY)) { int bytes = OctreePacketData::unpackDataFromBytes(dataAt, priority); @@ -590,9 +594,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // ownership has changed auto nodeList = DependencyManager::get(); if (_simulatorID == nodeList->getSessionUUID()) { - // we think we're the owner but entityServer says otherwise - // we only relenquish ownership if the incoming priority is greater than ours - if (priority > _simulatorPriority) { + // we think we're the owner but entityServer says otherwise we only relenquish + // ownership if the incoming priority is greater than or equal to ours + if (priority >= _simulatorPriority) { // we're losing simulation ownership _simulatorID = id; _simulatorPriority = priority; @@ -605,7 +609,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } } else if (priority != _simulatorPriority) { // This should be an uncommon event: priority is changing but simulatorID is not. - // But we only accept this change if we are NOT the simulator owner. + // We only accept this change if we are NOT the simulator owner, since otherwise + // we would have initiated this change. auto nodeList = DependencyManager::get(); if (_simulatorID != nodeList->getSessionUUID()) { _simulatorPriority = priority; From 82ba5cd4b64862c99910458b91130e26716b8785 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 12 Jun 2015 07:24:41 -0700 Subject: [PATCH 03/24] sim ownership uses expiry, apply priority rules --- libraries/entities/src/EntityItem.cpp | 29 ++++++++++++++++----------- libraries/entities/src/EntityItem.h | 4 ++-- libraries/entities/src/EntityTree.cpp | 17 +++++++++++++--- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 37164bd6f6..1e10ff2e48 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -27,6 +27,8 @@ #include "EntityTree.h" #include "EntitySimulation.h" +const quint64 SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND); + bool EntityItem::_sendPhysicsUpdates = true; EntityItem::EntityItem(const EntityItemID& entityItemID) : @@ -66,7 +68,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _userData(ENTITY_ITEM_DEFAULT_USER_DATA), _simulatorPriority(0), _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), - _simulatorIDChangedTime(0), + _simulationOwnershipExpiry(0), _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), _name(ENTITY_ITEM_DEFAULT_NAME), _href(""), @@ -594,23 +596,24 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // ownership has changed auto nodeList = DependencyManager::get(); if (_simulatorID == nodeList->getSessionUUID()) { - // we think we're the owner but entityServer says otherwise we only relenquish - // ownership if the incoming priority is greater than or equal to ours - if (priority >= _simulatorPriority) { + // we think we're the owner but entityServer says otherwise + // we relenquish ownership if the incoming priority is greater than or equal to ours + // AND we don't have max priority + if (priority >= _simulatorPriority && _simulatorPriority != MAX_SIMULATOR_PRIORITY) { // we're losing simulation ownership _simulatorID = id; _simulatorPriority = priority; - _simulatorIDChangedTime = usecTimestampNow(); + _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; } } else { _simulatorID = id; _simulatorPriority = priority; - _simulatorIDChangedTime = usecTimestampNow(); + _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; } } else if (priority != _simulatorPriority) { - // This should be an uncommon event: priority is changing but simulatorID is not. - // We only accept this change if we are NOT the simulator owner, since otherwise - // we would have initiated this change. + // priority is changing but simulatorID is not. + // only accept this change if we are NOT the simulator owner, since otherwise + // we would have initiated this change auto nodeList = DependencyManager::get(); if (_simulatorID != nodeList->getSessionUUID()) { _simulatorPriority = priority; @@ -1393,14 +1396,16 @@ void EntityItem::updateCreated(uint64_t value) { } void EntityItem::setSimulatorID(const QUuid& value) { - _simulatorID = value; - _simulatorIDChangedTime = usecTimestampNow(); + if (_simulatorID != value) { + _simulatorID = value; + _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; + } } void EntityItem::updateSimulatorID(const QUuid& value) { if (_simulatorID != value) { _simulatorID = value; - _simulatorIDChangedTime = usecTimestampNow(); + _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 135ac78617..fe82870992 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -326,7 +326,7 @@ public: QUuid getSimulatorID() const { return _simulatorID; } void setSimulatorID(const QUuid& value); void updateSimulatorID(const QUuid& value); - quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; } + const quint64& getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } const QString& getMarketplaceID() const { return _marketplaceID; } void setMarketplaceID(const QString& value) { _marketplaceID = value; } @@ -433,7 +433,7 @@ protected: QString _userData; uint8_t _simulatorPriority; QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity - quint64 _simulatorIDChangedTime; // when was _simulatorID last updated? + quint64 _simulationOwnershipExpiry; // time in future when ownership is back up for grabs QString _marketplaceID; QString _name; QString _href; //Hyperlink href diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 752082932b..a3ef5f9261 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -157,6 +157,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI if (entity->getSimulatorID() == senderID) { // We only allow the simulation owner to clear their own simulationID's. simulationBlocked = false; + properties.setSimulatorPriority(0); // clear priority irregardless of priority sent } // else: We assume the sender really did believe it was the simulation owner when it sent } else if (submittedID == senderID) { @@ -165,9 +166,18 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI simulationBlocked = false; } else { // the sender is trying to steal ownership from another simulator - // so we apply the ownership change filter - if (usecTimestampNow() - entity->getSimulatorIDChangedTime() > SIMULATOR_CHANGE_LOCKOUT_PERIOD) { - simulationBlocked = false; + // so we apply the rules for ownership change: + // (1) higher priority wins + // (2) equal priority wins if ownership filter has expired except... + // (3) max priority never loses + uint8_t oldPriority = entity->getSimulatorPriority(); + if (oldPriority != MAX_SIMULATOR_PRIORITY) { + uint8_t newPriority = properties.getSimulatorPriority(); + if (newPriority > oldPriority || + (newPriority == oldPriority && + usecTimestampNow() > entity->getSimulationOwnershipExpiry())) { + simulationBlocked = false; + } } } } else { @@ -177,6 +187,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI } if (simulationBlocked) { // squash the physics-related changes. + properties.setSimulatorPriorityChanged(false); properties.setSimulatorIDChanged(false); properties.setPositionChanged(false); properties.setRotationChanged(false); From d0ac3e45143a6d0a9845bf0ec0926f2a495d3019 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 12 Jun 2015 13:39:40 -0700 Subject: [PATCH 04/24] more work on simulator priority scripts that edit terse update data try to assert priority physics simulation tries to assert "volunteer" priority max priority rules are applied in entity server --- libraries/entities/src/EntityItem.cpp | 46 +++++++++++++++---- libraries/entities/src/EntityItem.h | 7 ++- .../entities/src/EntityItemProperties.cpp | 14 ++++++ libraries/entities/src/EntityItemProperties.h | 3 ++ .../entities/src/EntityScriptingInterface.cpp | 27 ++++++----- libraries/entities/src/EntityTree.cpp | 13 ++---- .../entities/src/SimpleEntitySimulation.cpp | 18 ++++---- .../entities/src/SimpleEntitySimulation.h | 2 +- libraries/physics/src/EntityMotionState.cpp | 16 +++++-- libraries/physics/src/EntityMotionState.h | 4 ++ 10 files changed, 104 insertions(+), 46 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1e10ff2e48..b3c7f47b4f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -27,7 +27,8 @@ #include "EntityTree.h" #include "EntitySimulation.h" -const quint64 SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND); +const quint64 DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND); +const quint64 MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD = 2 * USECS_PER_SECOND; bool EntityItem::_sendPhysicsUpdates = true; @@ -322,6 +323,7 @@ int EntityItem::expectedBytes() { } +// clients use this method to unpack FULL updates from entity-server int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { @@ -596,24 +598,22 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // ownership has changed auto nodeList = DependencyManager::get(); if (_simulatorID == nodeList->getSessionUUID()) { - // we think we're the owner but entityServer says otherwise - // we relenquish ownership if the incoming priority is greater than or equal to ours + // we think we're the simulation owner but entity-server says otherwise + // we relenquish ownership iff the incoming priority is greater than or equal to ours // AND we don't have max priority if (priority >= _simulatorPriority && _simulatorPriority != MAX_SIMULATOR_PRIORITY) { // we're losing simulation ownership _simulatorID = id; _simulatorPriority = priority; - _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; } } else { _simulatorID = id; _simulatorPriority = priority; - _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; } } else if (priority != _simulatorPriority) { // priority is changing but simulatorID is not. // only accept this change if we are NOT the simulator owner, since otherwise - // we would have initiated this change + // we would have initiated this priority auto nodeList = DependencyManager::get(); if (_simulatorID != nodeList->getSessionUUID()) { _simulatorPriority = priority; @@ -1395,21 +1395,51 @@ void EntityItem::updateCreated(uint64_t value) { } } +void EntityItem::setSimulatorPriority(uint8_t priority) { + _simulatorPriority = priority; + if (_simulatorPriority == MAX_SIMULATOR_PRIORITY) { + // we always extend the the ownership expiry for MAX_SIMULATOR_PRIORITY + _simulationOwnershipExpiry = usecTimestampNow() + MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD; + } else if (_simulatorPriority == 0) { + _simulationOwnershipExpiry = 0; + } +} + void EntityItem::setSimulatorID(const QUuid& value) { if (_simulatorID != value) { _simulatorID = value; - _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; + if (!_simulatorID.isNull()) { + // Note: this logic only works well if _simulatorPriority is properly set before this point + quint64 lockoutPeriod = (_simulatorPriority == MAX_SIMULATOR_PRIORITY) + ? MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD : DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD; + _simulationOwnershipExpiry = usecTimestampNow() + lockoutPeriod; + } } } void EntityItem::updateSimulatorID(const QUuid& value) { if (_simulatorID != value) { _simulatorID = value; - _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; + if (!_simulatorID.isNull()) { + // Note: this logic only works well if _simulatorPriority is properly set before this point + quint64 lockoutPeriod = (_simulatorPriority == MAX_SIMULATOR_PRIORITY) + ? MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD : DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD; + _simulationOwnershipExpiry = usecTimestampNow() + lockoutPeriod; + } _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } } +void EntityItem::clearSimulationOwnership() { + _simulatorPriority = 0; + _simulatorID = QUuid(); + _simulationOwnershipExpiry = 0; + // don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulatorOwnership() + // is only ever called entity-server-side and the flags are only used client-side + //_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; + +} + bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer action) { assert(action); const QUuid& actionID = action->getID(); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index fe82870992..eaae9949ec 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -60,8 +60,10 @@ const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; const float ACTIVATION_GRAVITY_DELTA = 0.1f; const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; -const uint8_t MIN_SIMULATOR_PRIORITY = 1; +const uint8_t VOLUNTEER_SIMULATOR_PRIORITY = 0x01; +const uint8_t SCRIPT_EDIT_SIMULATOR_PRIORITY = 0x80; const uint8_t MAX_SIMULATOR_PRIORITY = 0xff; +const uint8_t ATTACHMENT_SIMULATOR_PRIORITY = MAX_SIMULATOR_PRIORITY; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; @@ -320,13 +322,14 @@ public: const QString& getUserData() const { return _userData; } void setUserData(const QString& value) { _userData = value; } - void setSimulatorPriority(uint8_t priority) { _simulatorPriority = priority; } + void setSimulatorPriority(uint8_t priority); uint8_t getSimulatorPriority() const { return _simulatorPriority; } QUuid getSimulatorID() const { return _simulatorID; } void setSimulatorID(const QUuid& value); void updateSimulatorID(const QUuid& value); const quint64& getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } + void clearSimulationOwnership(); const QString& getMarketplaceID() const { return _marketplaceID; } void setMarketplaceID(const QString& value) { _marketplaceID = value; } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index b33889189f..7b2fdf1098 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1234,3 +1234,17 @@ bool EntityItemProperties::hasTerseUpdateChanges() const { // a TerseUpdate includes the transform and its derivatives return _positionChanged || _velocityChanged || _rotationChanged || _angularVelocityChanged || _accelerationChanged; } + +void EntityItemProperties::clearSimulatorOwnership() { + _simulatorID = QUuid(); + _simulatorPriority = 0; + _simulatorIDChanged = true; + _simulatorPriorityChanged = true; +} + +void EntityItemProperties::setSimulatorOwnership(const QUuid& id, uint8_t priority) { + _simulatorID = id; + _simulatorPriority = glm::max(priority, _simulatorPriority); + _simulatorIDChanged = true; + _simulatorPriorityChanged = true; +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6f2aca8d92..230cd5c122 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -207,6 +207,9 @@ public: bool hasTerseUpdateChanges() const; + void clearSimulatorOwnership(); + void setSimulatorOwnership(const QUuid& id, uint8_t priority); + private: QUuid _id; bool _idSet; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c9f7378bc8..aaedf5a5e9 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -61,16 +61,6 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) { } } -void bidForSimulationOwnership(EntityItemProperties& properties) { - // We make a bid for simulation ownership by declaring our sessionID as simulation owner - // in the outgoing properties. The EntityServer may accept the bid or might not. - auto nodeList = DependencyManager::get(); - const QUuid myNodeID = nodeList->getSessionUUID(); - properties.setSimulatorID(myNodeID); -} - - - QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) { EntityItemProperties propertiesWithSimID = properties; @@ -83,11 +73,15 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties _entityTree->lockForWrite(); EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID); if (entity) { - entity->setLastBroadcast(usecTimestampNow()); // This Node is creating a new object. If it's in motion, set this Node as the simulator. - bidForSimulationOwnership(propertiesWithSimID); + auto nodeList = DependencyManager::get(); + const QUuid myNodeID = nodeList->getSessionUUID(); + propertiesWithSimID.setSimulatorOwnership(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); + // and make note of it now, so we can act on it right away. entity->setSimulatorID(propertiesWithSimID.getSimulatorID()); + + entity->setLastBroadcast(usecTimestampNow()); } else { qCDebug(entities) << "script failed to add new Entity to local Octree"; success = false; @@ -160,9 +154,14 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper // balls" test. However, even if we solve this problem we still need to provide a "slerp the visible // proxy toward the true physical position" feature to hide the final glitches in the remote watcher's // simulation. + + // we re-assert our simulation ownership + properties.setSimulatorOwnership(myNodeID, + glm::max(entity->getSimulatorPriority(), SCRIPT_EDIT_SIMULATOR_PRIORITY)); + } else { + // we make a bid for simulation ownership + properties.setSimulatorOwnership(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); } - // we make a bid for (or assert existing) simulation ownership - properties.setSimulatorID(myNodeID); } entity->setLastBroadcast(usecTimestampNow()); } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a3ef5f9261..ab981862a1 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -169,15 +169,12 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI // so we apply the rules for ownership change: // (1) higher priority wins // (2) equal priority wins if ownership filter has expired except... - // (3) max priority never loses uint8_t oldPriority = entity->getSimulatorPriority(); - if (oldPriority != MAX_SIMULATOR_PRIORITY) { - uint8_t newPriority = properties.getSimulatorPriority(); - if (newPriority > oldPriority || - (newPriority == oldPriority && - usecTimestampNow() > entity->getSimulationOwnershipExpiry())) { - simulationBlocked = false; - } + uint8_t newPriority = properties.getSimulatorPriority(); + if (newPriority > oldPriority || + (newPriority == oldPriority && + usecTimestampNow() > entity->getSimulationOwnershipExpiry())) { + simulationBlocked = false; } } } else { diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 8dedbd2162..ff8d72b353 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -23,18 +23,18 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { // has finished simulating it. auto nodeList = DependencyManager::get(); - SetOfEntities::iterator itemItr = _hasSimulationOwnerEntities.begin(); - while (itemItr != _hasSimulationOwnerEntities.end()) { + SetOfEntities::iterator itemItr = _entitiesWithSimulator.begin(); + while (itemItr != _entitiesWithSimulator.end()) { EntityItemPointer entity = *itemItr; if (entity->getSimulatorID().isNull()) { - itemItr = _hasSimulationOwnerEntities.erase(itemItr); + itemItr = _entitiesWithSimulator.erase(itemItr); } else if (now - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) { SharedNodePointer ownerNode = nodeList->nodeWithUUID(entity->getSimulatorID()); if (ownerNode.isNull() || !ownerNode->isAlive()) { qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID(); // TODO: zero velocities when we clear simulatorID? - entity->setSimulatorID(QUuid()); - itemItr = _hasSimulationOwnerEntities.erase(itemItr); + entity->clearSimulationOwnership(); + itemItr = _entitiesWithSimulator.erase(itemItr); } else { ++itemItr; } @@ -47,23 +47,23 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) { EntitySimulation::addEntityInternal(entity); if (!entity->getSimulatorID().isNull()) { - _hasSimulationOwnerEntities.insert(entity); + _entitiesWithSimulator.insert(entity); } } void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) { - _hasSimulationOwnerEntities.remove(entity); + _entitiesWithSimulator.remove(entity); } void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { EntitySimulation::changeEntityInternal(entity); if (!entity->getSimulatorID().isNull()) { - _hasSimulationOwnerEntities.insert(entity); + _entitiesWithSimulator.insert(entity); } entity->clearDirtyFlags(); } void SimpleEntitySimulation::clearEntitiesInternal() { - _hasSimulationOwnerEntities.clear(); + _entitiesWithSimulator.clear(); } diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 6eb3980dd3..fff0659067 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -28,7 +28,7 @@ protected: virtual void changeEntityInternal(EntityItemPointer entity); virtual void clearEntitiesInternal(); - SetOfEntities _hasSimulationOwnerEntities; + SetOfEntities _entitiesWithSimulator; }; #endif // hifi_SimpleEntitySimulation_h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5e9591a031..9a65bac042 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -97,7 +97,9 @@ void EntityMotionState::handleEasyChanges(uint32_t flags) { assert(entityTreeIsLocked()); updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags); + if (flags & EntityItem::DIRTY_SIMULATOR_ID) { + _loopsSinceOwnershipBid = 0; _loopsWithoutOwner = 0; _candidateForOwnership = 0; if (_entity->getSimulatorID().isNull() @@ -453,14 +455,15 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q if (!active) { // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID // but we remember that we do still own it... and rely on the server to tell us that we don't - properties.setSimulatorID(QUuid()); + properties.clearSimulatorOwnership(); } else { - // explicitly set the property's simulatorID so that it is flagged as changed and will be packed - properties.setSimulatorID(sessionID); + // re-assert the simulation info + properties.setSimulatorOwnership(sessionID, _entity->getSimulatorPriority()); } } else { // we don't own the simulation for this entity yet, but we're sending a bid for it - properties.setSimulatorID(sessionID); + properties.setSimulatorOwnership(sessionID, glm::max(_simulatorPriorityHint, VOLUNTEER_SIMULATOR_PRIORITY)); + _simulatorPriorityHint = 0; } if (EntityItem::getSendPhysicsUpdates()) { @@ -580,3 +583,8 @@ int16_t EntityMotionState::computeCollisionGroup() { } return COLLISION_GROUP_DEFAULT; } + +void EntityMotionState::setSimulatorPriorityHint(uint8_t priority) { + _candidateForOwnership = true; + _simulatorPriorityHint = priority; +} diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 4f777a4575..d9350311b1 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -80,6 +80,9 @@ public: virtual int16_t computeCollisionGroup(); + // eternal logic can suggest a simuator priority bid for the next outgoing update + void setSimulatorPriorityHint(uint8_t priority); + friend class PhysicalEntitySimulation; protected: @@ -114,6 +117,7 @@ protected: bool _candidateForOwnership; uint32_t _loopsSinceOwnershipBid; uint32_t _loopsWithoutOwner; + uint8_t _simulatorPriorityHint; }; #endif // hifi_EntityMotionState_h From 7c793c6397837f384348f3208b06b625b1ed221d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 15 Jun 2015 10:58:14 -0700 Subject: [PATCH 05/24] accept simulation release from entity-server --- libraries/entities/src/EntityItem.cpp | 10 ++++++---- libraries/physics/src/EntityMotionState.cpp | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index b3c7f47b4f..82a843ff48 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -124,6 +124,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_USER_DATA; requestedProperties += PROP_MARKETPLACE_ID; requestedProperties += PROP_NAME; + requestedProperties += PROP_SIMULATOR_PRIORITY; requestedProperties += PROP_SIMULATOR_ID; requestedProperties += PROP_HREF; requestedProperties += PROP_DESCRIPTION; @@ -599,16 +600,17 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto nodeList = DependencyManager::get(); if (_simulatorID == nodeList->getSessionUUID()) { // we think we're the simulation owner but entity-server says otherwise - // we relenquish ownership iff the incoming priority is greater than or equal to ours - // AND we don't have max priority - if (priority >= _simulatorPriority && _simulatorPriority != MAX_SIMULATOR_PRIORITY) { + // we relenquish ownership only if we don't have MAX_SIMULATOR_PRIORITY + if (_simulatorPriority != MAX_SIMULATOR_PRIORITY) { // we're losing simulation ownership _simulatorID = id; _simulatorPriority = priority; + _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } } else { _simulatorID = id; _simulatorPriority = priority; + _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } } else if (priority != _simulatorPriority) { // priority is changing but simulatorID is not. @@ -967,8 +969,8 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulatorID, getSimulatorID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulatorPriority, getSimulatorPriority); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulatorID, getSimulatorID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName); COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 9a65bac042..246acd2efb 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -101,7 +101,7 @@ void EntityMotionState::handleEasyChanges(uint32_t flags) { if (flags & EntityItem::DIRTY_SIMULATOR_ID) { _loopsSinceOwnershipBid = 0; _loopsWithoutOwner = 0; - _candidateForOwnership = 0; + _candidateForOwnership = false; if (_entity->getSimulatorID().isNull() && !_entity->isMoving() && _body->isActive()) { From 2579247c348aff19aeeeefc466ef567311e247eb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 16 Jun 2015 09:15:51 -0700 Subject: [PATCH 06/24] claim ownership faster for scripted manipulations --- libraries/entities/src/EntityItem.h | 7 ++- .../entities/src/EntityScriptingInterface.cpp | 1 + libraries/physics/src/EntityMotionState.cpp | 59 ++++++++++--------- libraries/physics/src/EntityMotionState.h | 3 +- libraries/physics/src/ObjectMotionState.h | 2 +- 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index eaae9949ec..0dc7d2febf 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -96,8 +96,9 @@ public: DIRTY_LIFETIME = 0x0100, DIRTY_UPDATEABLE = 0x0200, DIRTY_MATERIAL = 0x00400, - DIRTY_PHYSICS_ACTIVATION = 0x0800, // we want to activate the object - DIRTY_SIMULATOR_ID = 0x1000, + DIRTY_PHYSICS_ACTIVATION = 0x0800, // should activate object in physics engine + DIRTY_SIMULATOR_OWNERSHIP = 0x1000, // should claim simulator ownership + DIRTY_SIMULATOR_ID = 0x2000, // the simulatorID has changed DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION, DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY }; @@ -387,6 +388,8 @@ public: void getAllTerseUpdateProperties(EntityItemProperties& properties) const; + void flagForOwnership() { _dirtyFlags |= DIRTY_SIMULATOR_OWNERSHIP; } + bool addAction(EntitySimulation* simulation, EntityActionPointer action); bool updateAction(EntitySimulation* simulation, const QUuid& actionID, const QVariantMap& arguments); bool removeAction(EntitySimulation* simulation, const QUuid& actionID); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index aaedf5a5e9..d2e8a46d27 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -161,6 +161,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper } else { // we make a bid for simulation ownership properties.setSimulatorOwnership(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); + entity->flagForOwnership(); } } entity->setLastBroadcast(usecTimestampNow()); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 246acd2efb..767431d8f5 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -58,8 +58,7 @@ bool entityTreeIsLocked() { EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) : ObjectMotionState(shape), _entity(entity), - _sentActive(false), - _numNonMovingUpdates(0), + _sentInactive(true), _lastStep(0), _serverPosition(0.0f), _serverRotation(), @@ -117,6 +116,13 @@ void EntityMotionState::handleEasyChanges(uint32_t flags) { } } } + if (flags & EntityItem::DIRTY_SIMULATOR_OWNERSHIP) { + // we're manipulating this object directly via script, so we artificially + // manipulate the logic to trigger an immediate bid for ownership + _candidateForOwnership = true; + _loopsSinceOwnershipBid = uint32_t(-1); + _loopsWithoutOwner = uint32_t(-1); + } if ((flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); } @@ -197,6 +203,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_loopsWithoutOwner > OWNERSHIP_BID_DELAY) { //qDebug() << "Warning -- claiming something I saw moving." << getName(); _candidateForOwnership = true; + _loopsSinceOwnershipBid = uint32_t(-1); } } else { _loopsWithoutOwner = 0; @@ -243,7 +250,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _serverVelocity = bulletToGLM(_body->getLinearVelocity()); _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); _lastStep = simulationStep; - _sentActive = false; + _sentInactive = true; return false; } @@ -257,7 +264,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; const float INACTIVE_UPDATE_PERIOD = 0.5f; - if (!_sentActive) { + if (_sentInactive) { // we resend the inactive update every INACTIVE_UPDATE_PERIOD // until it is removed from the outgoing updates // (which happens when we don't own the simulation and it isn't touching our simulation) @@ -345,30 +352,23 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s assert(_body); assert(entityTreeIsLocked()); - if (!remoteSimulationOutOfSync(simulationStep)) { - _candidateForOwnership = false; - return false; - } - - if (_entity->getSimulatorID() == sessionID) { - // we own the simulation - _candidateForOwnership = false; - return true; - } - - const uint32_t FRAMES_BETWEEN_OWNERSHIP_CLAIMS = 30; - if (_candidateForOwnership) { - _candidateForOwnership = false; - ++_loopsSinceOwnershipBid; - if (_loopsSinceOwnershipBid > FRAMES_BETWEEN_OWNERSHIP_CLAIMS) { - // we don't own the simulation, but it's time to bid for it - _loopsSinceOwnershipBid = 0; - return true; + if (_entity->getSimulatorID() != sessionID) { + // we don't own the simulation, but maybe we should... + if (_candidateForOwnership) { + _candidateForOwnership = false; + ++_loopsSinceOwnershipBid; + const uint32_t FRAMES_BETWEEN_OWNERSHIP_CLAIMS = 30; + if (_loopsSinceOwnershipBid > FRAMES_BETWEEN_OWNERSHIP_CLAIMS) { + // it's time to bid for ownership + _loopsSinceOwnershipBid = 0; + return true; + } } - } - + return false; + } _candidateForOwnership = false; - return false; + + return remoteSimulationOutOfSync(simulationStep); } void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) { @@ -382,7 +382,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q _entity->setVelocity(zero); _entity->setAngularVelocity(zero); _entity->setAcceleration(zero); - _sentActive = false; + _sentInactive = true; } else { float gravityLength = glm::length(_entity->getGravity()); float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); @@ -419,7 +419,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q _entity->setVelocity(zero); _entity->setAngularVelocity(zero); } - _sentActive = true; + _sentInactive = false; } // remember properties for local server prediction @@ -543,8 +543,11 @@ void EntityMotionState::measureBodyAcceleration() { _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt; _lastVelocity = velocity; if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS && !_candidateForOwnership) { + // object has just been re-activated so clear ownership logic _loopsSinceOwnershipBid = 0; _loopsWithoutOwner = 0; + _lastStep = ObjectMotionState::getWorldSimulationStep(); + _sentInactive = false; } } } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index d9350311b1..109c041d93 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -96,8 +96,7 @@ protected: EntityItemPointer _entity; - bool _sentActive; // true if body was active when we sent last update - int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects + bool _sentInactive; // true if body was inactive when we sent last update // these are for the prediction of the remote server's simple extrapolation uint32_t _lastStep; // last step of server extrapolation diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 561ce02d62..502efb5f98 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -40,7 +40,7 @@ enum MotionStateType { const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | - EntityItem::DIRTY_MATERIAL); + EntityItem::DIRTY_MATERIAL | EntityItem::DIRTY_SIMULATOR_OWNERSHIP); // These are the set of incoming flags that the PhysicsEngine needs to hear about: const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | From 8510110324b09a7bc34d5ae19b97e372016e079a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 16 Jun 2015 09:46:24 -0700 Subject: [PATCH 07/24] increase sim priority when flagged for ownership --- libraries/physics/src/EntityMotionState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 767431d8f5..d82185ff19 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -122,6 +122,7 @@ void EntityMotionState::handleEasyChanges(uint32_t flags) { _candidateForOwnership = true; _loopsSinceOwnershipBid = uint32_t(-1); _loopsWithoutOwner = uint32_t(-1); + _simulatorPriorityHint = SCRIPT_EDIT_SIMULATOR_PRIORITY; } if ((flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); From a33c350385eb366f2594f04db6ad6b21e8d77f45 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 16 Jun 2015 11:38:34 -0700 Subject: [PATCH 08/24] improved forcing of simulator ownership bid --- libraries/physics/src/EntityMotionState.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d82185ff19..804890bf20 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -26,6 +26,8 @@ static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; +const uint32_t LOOPS_FOR_SIMULATION_ORPHAN = 50; +const uint32_t LOOPS_BETWEEN_OWNERSHIP_BIDS = 30; #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS bool EntityMotionState::entityTreeIsLocked() const { @@ -120,8 +122,8 @@ void EntityMotionState::handleEasyChanges(uint32_t flags) { // we're manipulating this object directly via script, so we artificially // manipulate the logic to trigger an immediate bid for ownership _candidateForOwnership = true; - _loopsSinceOwnershipBid = uint32_t(-1); - _loopsWithoutOwner = uint32_t(-1); + _loopsSinceOwnershipBid = LOOPS_BETWEEN_OWNERSHIP_BIDS; + _loopsWithoutOwner = LOOPS_FOR_SIMULATION_ORPHAN; _simulatorPriorityHint = SCRIPT_EDIT_SIMULATOR_PRIORITY; } if ((flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { @@ -200,11 +202,10 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_entity->getSimulatorID().isNull()) { _loopsWithoutOwner++; - const uint32_t OWNERSHIP_BID_DELAY = 50; - if (_loopsWithoutOwner > OWNERSHIP_BID_DELAY) { + if (_loopsWithoutOwner > LOOPS_FOR_SIMULATION_ORPHAN) { //qDebug() << "Warning -- claiming something I saw moving." << getName(); _candidateForOwnership = true; - _loopsSinceOwnershipBid = uint32_t(-1); + _loopsSinceOwnershipBid = LOOPS_BETWEEN_OWNERSHIP_BIDS + 1; } } else { _loopsWithoutOwner = 0; @@ -358,8 +359,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s if (_candidateForOwnership) { _candidateForOwnership = false; ++_loopsSinceOwnershipBid; - const uint32_t FRAMES_BETWEEN_OWNERSHIP_CLAIMS = 30; - if (_loopsSinceOwnershipBid > FRAMES_BETWEEN_OWNERSHIP_CLAIMS) { + if (_loopsSinceOwnershipBid > LOOPS_BETWEEN_OWNERSHIP_BIDS) { // it's time to bid for ownership _loopsSinceOwnershipBid = 0; return true; From 4b299072169c7aebf013619cfe35718c8cf283c6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 16 Jun 2015 11:39:55 -0700 Subject: [PATCH 09/24] trigger bid for ownership on action manipulations --- libraries/entities/src/EntityScriptingInterface.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index d2e8a46d27..3751f85821 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -558,6 +558,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, return false; } if (actionFactory->factory(simulation, actionType, actionID, entity, arguments)) { + entity->flagForOwnership(); return true; } return false; @@ -571,7 +572,11 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& actionID, const QVariantMap& arguments) { return actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) { - return entity->updateAction(simulation, actionID, arguments); + bool success = entity->updateAction(simulation, actionID, arguments); + if (success) { + entity->flagForOwnership(); + } + return success; }); } From c87e7c99ce4e4a15ad655e02cd37063bb7c22f6d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 16 Jun 2015 17:49:44 -0700 Subject: [PATCH 10/24] bid for ownership on script-change phys properties --- libraries/entities/src/EntityItem.h | 2 +- .../entities/src/EntityItemProperties.cpp | 6 ++++++ libraries/entities/src/EntityItemProperties.h | 1 + .../entities/src/EntityScriptingInterface.cpp | 20 +++++++++++++++---- libraries/shared/src/PhysicsHelpers.h | 2 +- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0dc7d2febf..77531c59cf 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -367,7 +367,7 @@ public: virtual void updateShapeType(ShapeType type) { /* do nothing */ } uint32_t getDirtyFlags() const { return _dirtyFlags; } - void clearDirtyFlags(uint32_t mask = 0xffff) { _dirtyFlags &= ~mask; } + void clearDirtyFlags(uint32_t mask = 0xffffffff) { _dirtyFlags &= ~mask; } bool isMoving() const; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7b2fdf1098..4003288700 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1235,6 +1235,12 @@ bool EntityItemProperties::hasTerseUpdateChanges() const { return _positionChanged || _velocityChanged || _rotationChanged || _angularVelocityChanged || _accelerationChanged; } +bool EntityItemProperties::hasMiscPhysicsChanges() const { + return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged + || _restitutionChanged || _dampingChanged || _angularDampingChanged || _registrationPointChanged || + _compoundShapeURLChanged || _collisionsWillMoveChanged || _ignoreForCollisionsChanged; +} + void EntityItemProperties::clearSimulatorOwnership() { _simulatorID = QUuid(); _simulatorPriority = 0; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 230cd5c122..4210b342f2 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -206,6 +206,7 @@ public: void setCreated(QDateTime& v); bool hasTerseUpdateChanges() const; + bool hasMiscPhysicsChanges() const; void clearSimulatorOwnership(); void setSimulatorOwnership(const QUuid& id, uint8_t priority); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 3751f85821..6786763a83 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -140,13 +140,17 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper if (entity) { // make sure the properties has a type, so that the encode can know which properties to include properties.setType(entity->getType()); - if (properties.hasTerseUpdateChanges()) { + bool hasTerseUpdateChanges = properties.hasTerseUpdateChanges(); + bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTerseUpdateChanges; + if (hasPhysicsChanges) { auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); if (entity->getSimulatorID() == myNodeID) { // we think we already own the simulation, so make sure to send ALL TerseUpdate properties - entity->getAllTerseUpdateProperties(properties); + if (hasTerseUpdateChanges) { + entity->getAllTerseUpdateProperties(properties); + } // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update // and instead let the physics simulation decide when to send a terse update. This would remove @@ -558,7 +562,11 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, return false; } if (actionFactory->factory(simulation, actionType, actionID, entity, arguments)) { - entity->flagForOwnership(); + auto nodeList = DependencyManager::get(); + const QUuid myNodeID = nodeList->getSessionUUID(); + if (entity->getSimulatorID() != myNodeID) { + entity->flagForOwnership(); + } return true; } return false; @@ -574,7 +582,11 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& return actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) { bool success = entity->updateAction(simulation, actionID, arguments); if (success) { - entity->flagForOwnership(); + auto nodeList = DependencyManager::get(); + const QUuid myNodeID = nodeList->getSessionUUID(); + if (entity->getSimulatorID() != myNodeID) { + entity->flagForOwnership(); + } } return success; }); diff --git a/libraries/shared/src/PhysicsHelpers.h b/libraries/shared/src/PhysicsHelpers.h index 0e58ae99f0..7ceafea915 100644 --- a/libraries/shared/src/PhysicsHelpers.h +++ b/libraries/shared/src/PhysicsHelpers.h @@ -15,7 +15,7 @@ #include #include -const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 4; +const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS. const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f; // return incremental rotation (Bullet-style) caused by angularVelocity over timeStep From cf74dbe1dc72586db6cf95025102cc2e175f472c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 19 Jun 2015 10:16:22 -0700 Subject: [PATCH 11/24] partial progress toward sim ownership negotiations works well for just a few objects but fails for piles committing some debug stuff that will have to be torn out later --- interface/src/avatar/AvatarMotionState.cpp | 4 - interface/src/avatar/AvatarMotionState.h | 1 - libraries/entities/src/EntityItem.cpp | 98 ++++++++++--- libraries/entities/src/EntityItem.h | 25 +++- .../entities/src/EntityItemProperties.cpp | 95 ++++++++++++ libraries/entities/src/EntityTree.cpp | 1 + libraries/octree/src/OctreePacketData.h | 2 + libraries/physics/src/EntityMotionState.cpp | 137 ++++++++++++------ libraries/physics/src/EntityMotionState.h | 12 +- libraries/physics/src/ObjectMotionState.cpp | 6 +- libraries/physics/src/ObjectMotionState.h | 8 +- libraries/physics/src/PhysicsEngine.cpp | 21 ++- 12 files changed, 319 insertions(+), 91 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 06da384a94..b106ee6398 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -148,10 +148,6 @@ QUuid AvatarMotionState::getSimulatorID() const { return _avatar->getSessionUUID(); } -// virtual -void AvatarMotionState::bump() { -} - // virtual int16_t AvatarMotionState::computeCollisionGroup() { return COLLISION_GROUP_OTHER_AVATAR; diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 79a4d23179..ac813e764c 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -55,7 +55,6 @@ public: virtual const QUuid& getObjectID() const; virtual QUuid getSimulatorID() const; - virtual void bump(); void setBoundingBox(const glm::vec3& corner, const glm::vec3& diagonal); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 82a843ff48..888ca239e2 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -27,6 +27,8 @@ #include "EntityTree.h" #include "EntitySimulation.h" +const char* plankyBlock2 = "PlankyBlock46"; // adebug + const quint64 DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND); const quint64 MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD = 2 * USECS_PER_SECOND; @@ -581,11 +583,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // rules that we expect the server to be using, so it is possible that we'll sometimes ignore // the incoming _simulatorID data (e.g. we might know something that the server does not... yet). + int requiredProperties = 1; // adebug uint8_t priority = 0; if (propertyFlags.getHasProperty(PROP_SIMULATOR_PRIORITY)) { int bytes = OctreePacketData::unpackDataFromBytes(dataAt, priority); dataAt += bytes; bytesRead += bytes; + requiredProperties *= 3; // adebug } QUuid id; @@ -593,32 +597,66 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef int bytes = OctreePacketData::unpackDataFromBytes(dataAt, id); dataAt += bytes; bytesRead += bytes; + requiredProperties *= 7; } - if (_simulatorID != id) { - // ownership has changed - auto nodeList = DependencyManager::get(); - if (_simulatorID == nodeList->getSessionUUID()) { - // we think we're the simulation owner but entity-server says otherwise - // we relenquish ownership only if we don't have MAX_SIMULATOR_PRIORITY - if (_simulatorPriority != MAX_SIMULATOR_PRIORITY) { - // we're losing simulation ownership + // adebug + if (requiredProperties == 3) { + std::cout << "adebug split properties for '" << _name.toStdString() << "' with priority only" << std::endl; // adebug + } + else if (requiredProperties == 7) { + std::cout << "adebug split properties for '" << _name.toStdString() << "' with id only" << std::endl; // adebug + } + + // TODO: refactor simulation ownership info to be a single property + if (requiredProperties == 3*7) { + if (_simulatorID != id) { + // ownership has changed + auto nodeList = DependencyManager::get(); + if (_simulatorID == nodeList->getSessionUUID()) { + // we think we're the simulation owner but entity-server says otherwise + // we relenquish ownership only if we don't have MAX_SIMULATOR_PRIORITY + if (_simulatorPriority != MAX_SIMULATOR_PRIORITY) { + // we're losing simulation ownership + if (_name == plankyBlock2) { + std::cout << "adebug lose ownership of '" << _name.toStdString() << "' to " << id.toString().toStdString() << " with priority " << int(priority) << std::endl; // adebug + } + _simulatorID = id; + _simulatorPriority = priority; + if (! (_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID)) { + if (_name == plankyBlock2) { + std::cout << "adebug setting DIRTY_SIMULATOR_ID while losing ownership" << std::endl; // adebug + } + } + _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; + } + } else { + auto nodeList = DependencyManager::get(); + if (id == nodeList->getSessionUUID()) { + if (_name == plankyBlock2) { + std::cout << "adebug gain ownership of '" << _name.toStdString() << "' id " << id.toString().toStdString() << " with priority " << int(priority) << std::endl; // adebug + } + } _simulatorID = id; _simulatorPriority = priority; + if (! (_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID)) { + if (_name == plankyBlock2) { + std::cout << "adebug setting DIRTY_SIMULATOR_ID with ownership of " << _simulatorID.toString().toStdString() << std::endl; // adebug + } + } _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } - } else { - _simulatorID = id; - _simulatorPriority = priority; - _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; - } - } else if (priority != _simulatorPriority) { - // priority is changing but simulatorID is not. - // only accept this change if we are NOT the simulator owner, since otherwise - // we would have initiated this priority - auto nodeList = DependencyManager::get(); - if (_simulatorID != nodeList->getSessionUUID()) { - _simulatorPriority = priority; + } else if (priority != _simulatorPriority) { + // priority is changing but simulatorID is not. + // only accept this change if we are NOT the simulator owner, since otherwise + // we would have initiated this priority + auto nodeList = DependencyManager::get(); + if (_simulatorID != nodeList->getSessionUUID()) { + if (_name == plankyBlock2) { + std::cout << "adebug priority of '" << _name.toStdString() << "' changing from " << int(_simulatorPriority) << " to " << int(priority) << std::endl; // adebug + } + _simulatorPriority = priority; + } } } } else if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { @@ -904,6 +942,11 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { } } +void EntityItem::clearDirtyFlags(uint32_t mask) { + // adebug TODO: move this back to header after done debugging + _dirtyFlags &= ~mask; +} + bool EntityItem::isMoving() const { return hasVelocity() || hasAngularVelocity(); } @@ -1039,6 +1082,9 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); if (somethingChanged) { + if (_name == plankyBlock2) { + std::cout << "adebug update for '" << _name.toStdString() << "'" << std::endl; // adebug + } uint64_t now = usecTimestampNow(); #ifdef WANT_DEBUG int elapsed = now - getLastEdited(); @@ -1398,6 +1444,9 @@ void EntityItem::updateCreated(uint64_t value) { } void EntityItem::setSimulatorPriority(uint8_t priority) { + if (_name == plankyBlock2) { + std::cout << "adebug setSimulatorPriority() for '" << _name.toStdString() << "' from " << int(_simulatorPriority) << " to " << int(priority) << std::endl; // adebug + } _simulatorPriority = priority; if (_simulatorPriority == MAX_SIMULATOR_PRIORITY) { // we always extend the the ownership expiry for MAX_SIMULATOR_PRIORITY @@ -1409,6 +1458,9 @@ void EntityItem::setSimulatorPriority(uint8_t priority) { void EntityItem::setSimulatorID(const QUuid& value) { if (_simulatorID != value) { + if (_name == plankyBlock2) { + std::cout << "adebug setSimulatorID for '" << _name.toStdString() << "' from " << _simulatorID.toString().toStdString() << " to " << value.toString().toStdString() << std::endl; // adebug + } _simulatorID = value; if (!_simulatorID.isNull()) { // Note: this logic only works well if _simulatorPriority is properly set before this point @@ -1421,6 +1473,9 @@ void EntityItem::setSimulatorID(const QUuid& value) { void EntityItem::updateSimulatorID(const QUuid& value) { if (_simulatorID != value) { + if (_name == plankyBlock2) { + std::cout << "adebug updateSimulatorID for '" << _name.toStdString() << "' from " << _simulatorID.toString().toStdString() << " to " << value.toString().toStdString() << std::endl; // adebug + } _simulatorID = value; if (!_simulatorID.isNull()) { // Note: this logic only works well if _simulatorPriority is properly set before this point @@ -1433,6 +1488,9 @@ void EntityItem::updateSimulatorID(const QUuid& value) { } void EntityItem::clearSimulationOwnership() { + if (_name == plankyBlock2) { + std::cout << "adebug clearSimulationOwnership for '" << _name.toStdString() << "'" << std::endl; // adebug + } _simulatorPriority = 0; _simulatorID = QUuid(); _simulationOwnershipExpiry = 0; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 77531c59cf..2c62588913 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -72,6 +72,28 @@ const uint8_t ATTACHMENT_SIMULATOR_PRIORITY = MAX_SIMULATOR_PRIORITY; #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) #define debugTreeVector(V) V << "[" << V << " in meters ]" +class SimulationOwner { +public: + SimulationOwner() : _id(), _priority(0) {} + SimulationOwner(const QUuid& id, uint8_t priority) : _id(id), _priority(priority) {} + + const QUuid& getID() const { return _id; } + uint8_t getPriority() const { return _priority; } + + void clear() { _id = QUuid(); _priority = 0; } + void set(const QUuid& id, uint8_t priority) { _id = id; _priority = priority; } + + bool isNull() const { return _id.isNull(); } + bool matchesID(const QUuid& id) const { return _id == id; } + //void toQByteArray(); + + bool operator>=(uint8_t priority) const { return _priority >= priority; } + +private: + QUuid _id; + uint8_t _priority; +}; + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate @@ -367,7 +389,8 @@ public: virtual void updateShapeType(ShapeType type) { /* do nothing */ } uint32_t getDirtyFlags() const { return _dirtyFlags; } - void clearDirtyFlags(uint32_t mask = 0xffffffff) { _dirtyFlags &= ~mask; } + //void clearDirtyFlags(uint32_t mask = 0xffffffff) { _dirtyFlags &= ~mask; } + void clearDirtyFlags(uint32_t mask = 0xffffffff); bool isMoving() const; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 4003288700..8d9b703874 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -325,6 +325,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked); CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures); CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData); + // TODO: combine these as one property CHECK_PROPERTY_CHANGE(PROP_SIMULATOR_PRIORITY, simulatorPriority); CHECK_PROPERTY_CHANGE(PROP_SIMULATOR_ID, simulatorID); CHECK_PROPERTY_CHANGE(PROP_TEXT, text); @@ -709,6 +710,42 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, +/* TODO: remove this old experiment code + // simulation ownership data needs to get back ASAP, and affects whether the "terse update" + // data will be accepted at the receiving end, so we put it at the front. +// if (requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY) && +// requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { +// QByteArray ownershipData = properties.getSimulatorID().toRfc4122(); +// ownershipData.append(properties.getSimulatorPriority(); +// LevelDetails propertyLevel = packetData->startLevel(); +// if (packetData->appendRawData(ownershipData)) { +// propertyFlags |= PROP_SIMULATOR_PRIORITY; +// propertiesDidntFit -= PROP_SIMULATOR_PRIORITY; +// propertyCount++; +// +// propertyFlags |= PROP_SIMULATOR_ID; +// propertiesDidntFit -= PROP_SIMULATOR_ID; +// propertyCount++; +// +// packetData->endLevel(propertyLevel); +// } +// } + // BOOKMARK -- replace the two ownership properties with one... at the EntityProperties level + // but make it two properties at the EntityItem + if (requestedProperties.getHasProperty(PROP_SIMULATOR_OWNERSHIP)) { + QByteArray ownershipData = properties.getSimulatorID().toRfc4122(); + ownershipData.append(properties.getSimulatorPriority(); + LevelDetails propertyLevel = packetData->startLevel(); + if (packetData->appendRawData(ownershipData)) { + propertyFlags |= PROP_SIMULATOR_OWNERSHIP; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + propertiesDidntFit -= PROP_SIMULATOR_OWNERSHIP; + } + } + */ + APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition()); APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete APPEND_ENTITY_PROPERTY(PROP_ROTATION, properties.getRotation()); @@ -733,6 +770,64 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_PRIORITY, properties.getSimulatorPriority()); APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, properties.getSimulatorID()); +/* TODO remove this experiment too + if (requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY) && + requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { + + QByteArray bytes = properties.getSimulatorID().toRfc4122(); + if (packetData->canAppendBytes(1 + bytes.size())) { + APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_PRIORITY, properties.getSimulatorPriority()); + APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, properties.getSimulatorID()); + } else { + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = false; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } + } + if (!requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY)) { + propertiesDidntFit -= PROP_SIMULATOR_PRIORITY; + } + if (!requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { + propertiesDidntFit -= PROP_SIMULATOR_ID; + } + } +*/ +/* and this one + //#define APPEND_ENTITY_PROPERTY(P,V) + if (requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY) && + requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { + + LevelDetails propertyLevel = packetData->startLevel(); + + QByteArray bytes = properties.getSimulatorID().toRfc4122(); + if (packetData->canAppendBytes(10 + bytes.size())) { + packetData->appendValue(properties.getSimulatorPriority()); + propertyFlags |= PROP_SIMULATOR_PRIORITY; + propertiesDidntFit -= PROP_SIMULATOR_PRIORITY; + propertyCount++; + packetData->endLevel(propertyLevel); + + propertyLevel = packetData->startLevel(); + packetData->appendValue(properties.getSimulatorID()); + propertyFlags |= PROP_SIMULATOR_ID; + propertiesDidntFit -= PROP_SIMULATOR_ID; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + successPropertyFits = false; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } + } else { + if (!requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY)) { + propertiesDidntFit -= PROP_SIMULATOR_PRIORITY; + } + if (!requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { + propertiesDidntFit -= PROP_SIMULATOR_ID; + } + } +*/ APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ab981862a1..4a03b0a6df 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -203,6 +203,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI uint32_t newFlags = entity->getDirtyFlags() & ~preFlags; if (newFlags) { if (_simulation) { + std::cout << "adebug newFlags & DIRTY_SIMULATION_FLAGS = 0x" << std::hex << (newFlags & DIRTY_SIMULATION_FLAGS) << std::dec << std::endl; // adebug if (newFlags & DIRTY_SIMULATION_FLAGS) { _simulation->lock(); _simulation->changeEntity(entity); diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 9476fe024e..1dc66b23ca 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -188,6 +188,8 @@ public: bool appendRawData(const unsigned char* data, int length); bool appendRawData(QByteArray data); + bool canAppendBytes(int numBytes) const { return _bytesAvailable > numBytes; } + /// returns a byte offset from beginning of the uncompressed stream based on offset from end. /// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 804890bf20..f2f5991124 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -22,12 +22,14 @@ #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS #include "EntityTree.h" #endif +const char* plankyBlock = "PlankyBlock46"; // adebug static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; const uint32_t LOOPS_FOR_SIMULATION_ORPHAN = 50; -const uint32_t LOOPS_BETWEEN_OWNERSHIP_BIDS = 30; +//const uint32_t LOOPS_BETWEEN_OWNERSHIP_BIDS = 30; +const quint64 USECS_BETWEEN_OWNERSHIP_BIDS = USECS_PER_SECOND / 5; #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS bool EntityMotionState::entityTreeIsLocked() const { @@ -69,8 +71,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer _serverGravity(0.0f), _serverAcceleration(0.0f), _accelerationNearlyGravityCount(0), - _candidateForOwnership(false), - _loopsSinceOwnershipBid(0), + _nextOwnershipBid(0), _loopsWithoutOwner(0) { _type = MOTIONSTATE_TYPE_ENTITY; @@ -94,37 +95,55 @@ void EntityMotionState::updateServerPhysicsVariables() { } // virtual -void EntityMotionState::handleEasyChanges(uint32_t flags) { +void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) { assert(entityTreeIsLocked()); + if (_entity && _entity->getName() == plankyBlock) { + quint64 dt = (usecTimestampNow() - _activationTime) / 1000; // adebug + std::cout << "adebug handleEasyChanges flags = 0x" << std::hex << flags << std::dec << " dt = " << dt << std::endl; // adebug + } updateServerPhysicsVariables(); - ObjectMotionState::handleEasyChanges(flags); + ObjectMotionState::handleEasyChanges(flags, engine); if (flags & EntityItem::DIRTY_SIMULATOR_ID) { - _loopsSinceOwnershipBid = 0; + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' found DIRTY_SIMULATOR_ID flag" << std::endl; // adebug + } _loopsWithoutOwner = 0; - _candidateForOwnership = false; - if (_entity->getSimulatorID().isNull() - && !_entity->isMoving() - && _body->isActive()) { + if (_entity->getSimulatorID().isNull()) { + // simulation ownership is being removed // remove the ACTIVATION flag because this object is coming to rest // according to a remote simulation and we don't want to wake it up again flags &= ~EntityItem::DIRTY_PHYSICS_ACTIVATION; + // hint to Bullet that the object is deactivating _body->setActivationState(WANTS_DEACTIVATION); - } else { - auto nodeList = DependencyManager::get(); - const QUuid& sessionID = nodeList->getSessionUUID(); - if (_entity->getSimulatorID() != sessionID) { - _loopsSinceOwnershipBid = 0; + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' clearing ownership so _candidatePriority goes to 0" << std::endl; // adebug + } + _candidatePriority = 0; + if (_expectedOwnership != -1) { + std::cout << "adebug unexpected loss of ownership '" << _entity->getName().toStdString() << "' expected -1 but got " << _expectedOwnership << std::endl; // adebug + } + _expectedOwnership = 0; + } else { + _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; + if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulatorPriority() > _candidatePriority) { + // we own the simulation or our priority looses to remote + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' we own it so _candidatePriority goes to 0" << std::endl; // adebug + } + if (_expectedOwnership != 1) { + std::cout << "adebug unexpected gain of ownership '" << _entity->getName().toStdString() << "' expected 1 but got " << _expectedOwnership << " _candidatePriority = " << int(_candidatePriority) << std::endl; // adebug + } + _expectedOwnership = 0; + _candidatePriority = 0; } } } if (flags & EntityItem::DIRTY_SIMULATOR_OWNERSHIP) { + // also known as "bid for ownership with SCRIPT priority" // we're manipulating this object directly via script, so we artificially // manipulate the logic to trigger an immediate bid for ownership - _candidateForOwnership = true; - _loopsSinceOwnershipBid = LOOPS_BETWEEN_OWNERSHIP_BIDS; - _loopsWithoutOwner = LOOPS_FOR_SIMULATION_ORPHAN; - _simulatorPriorityHint = SCRIPT_EDIT_SIMULATOR_PRIORITY; + setSimulatorPriorityHint(SCRIPT_EDIT_SIMULATOR_PRIORITY); } if ((flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); @@ -202,13 +221,14 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_entity->getSimulatorID().isNull()) { _loopsWithoutOwner++; - if (_loopsWithoutOwner > LOOPS_FOR_SIMULATION_ORPHAN) { + if (_loopsWithoutOwner > LOOPS_FOR_SIMULATION_ORPHAN && usecTimestampNow() > _nextOwnershipBid) { //qDebug() << "Warning -- claiming something I saw moving." << getName(); - _candidateForOwnership = true; - _loopsSinceOwnershipBid = LOOPS_BETWEEN_OWNERSHIP_BIDS + 1; + quint64 dt = (usecTimestampNow() - _activationTime) / 1000; // adebug + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug setWorldTransform() bid for orphan '" << _entity->getName().toStdString() << "' dt = " << dt << std::endl; // adebug + } + setSimulatorPriorityHint(VOLUNTEER_SIMULATOR_PRIORITY); } - } else { - _loopsWithoutOwner = 0; } #ifdef WANT_DEBUG @@ -239,7 +259,7 @@ bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const { return false; } assert(entityTreeIsLocked()); - return _candidateForOwnership || sessionID == _entity->getSimulatorID(); + return _candidatePriority > 0 || sessionID == _entity->getSimulatorID(); } bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { @@ -356,18 +376,19 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s if (_entity->getSimulatorID() != sessionID) { // we don't own the simulation, but maybe we should... - if (_candidateForOwnership) { - _candidateForOwnership = false; - ++_loopsSinceOwnershipBid; - if (_loopsSinceOwnershipBid > LOOPS_BETWEEN_OWNERSHIP_BIDS) { - // it's time to bid for ownership - _loopsSinceOwnershipBid = 0; - return true; + if (_candidatePriority > 0) { + if (_candidatePriority < _entity->getSimulatorPriority()) { + // our priority looses to remote, so we don't bother to bid + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug shouldSendUpdate() '" << _entity->getName().toStdString() << "' clear priority " << int(_candidatePriority) << " in favor of remote priority " << int(_entity->getSimulatorPriority()) << std::endl; // adebug + } + _candidatePriority = 0; + return false; } + return usecTimestampNow() > _nextOwnershipBid; } return false; } - _candidateForOwnership = false; return remoteSimulationOutOfSync(simulationStep); } @@ -456,15 +477,28 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q if (!active) { // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID // but we remember that we do still own it... and rely on the server to tell us that we don't + std::cout << "adebug releasing ownership of '" << _entity->getName().toStdString() << "' for inactivity" << std::endl; // adebug properties.clearSimulatorOwnership(); + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug sendUpdate() send clear ownership for '" << _entity->getName().toStdString() << "'" << std::endl; // adebug + } + _expectedOwnership = -1; } else { // re-assert the simulation info properties.setSimulatorOwnership(sessionID, _entity->getSimulatorPriority()); + _expectedOwnership = 0; } } else { // we don't own the simulation for this entity yet, but we're sending a bid for it - properties.setSimulatorOwnership(sessionID, glm::max(_simulatorPriorityHint, VOLUNTEER_SIMULATOR_PRIORITY)); - _simulatorPriorityHint = 0; + quint64 dt = (usecTimestampNow() - _activationTime) / 1000; // adebug + uint8_t bidPriority = glm::max(_candidatePriority, VOLUNTEER_SIMULATOR_PRIORITY); // adebug + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug sendUpdate() bid for ownership of '" << _entity->getName().toStdString() << "' dt = " << dt << " with priority " << int(bidPriority) << std::endl; // adebug + } + properties.setSimulatorOwnership(sessionID, glm::max(_candidatePriority, VOLUNTEER_SIMULATOR_PRIORITY)); + _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; + _expectedOwnership = 1; + //_candidatePriority = 0; // TODO: it would be nice to not have to clear this until we get a message back that ownership has changed } if (EntityItem::getSendPhysicsUpdates()) { @@ -502,6 +536,13 @@ uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() { return dirtyFlags; } +// virtual +uint8_t EntityMotionState::getSimulatorPriority() const { + if (_entity) { + return _entity->getSimulatorPriority(); + } + return 0; +} // virtual QUuid EntityMotionState::getSimulatorID() const { @@ -512,10 +553,13 @@ QUuid EntityMotionState::getSimulatorID() const { return QUuid(); } - // virtual -void EntityMotionState::bump() { - _candidateForOwnership = true; +void EntityMotionState::bump(uint8_t priority) { + if (_entity) { + //uint8_t inheritedPriority = priority < 2 ? 1 : priority - 1; + uint8_t inheritedPriority = VOLUNTEER_SIMULATOR_PRIORITY; + setSimulatorPriorityHint(inheritedPriority); + } } void EntityMotionState::resetMeasuredBodyAcceleration() { @@ -543,9 +587,11 @@ void EntityMotionState::measureBodyAcceleration() { glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity()); _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt; _lastVelocity = velocity; - if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS && !_candidateForOwnership) { - // object has just been re-activated so clear ownership logic - _loopsSinceOwnershipBid = 0; + if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) { + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug measureBodyAcceleration() activate '" << _entity->getName().toStdString() << "'" << std::endl; // adebug + } + _activationTime = usecTimestampNow(); // adebug _loopsWithoutOwner = 0; _lastStep = ObjectMotionState::getWorldSimulationStep(); _sentInactive = false; @@ -589,6 +635,11 @@ int16_t EntityMotionState::computeCollisionGroup() { } void EntityMotionState::setSimulatorPriorityHint(uint8_t priority) { - _candidateForOwnership = true; - _simulatorPriorityHint = priority; + uint8_t oldPriority = _candidatePriority; + _candidatePriority = glm::max(_candidatePriority, priority); + if (_candidatePriority != oldPriority) { + if (_entity && _entity->getName() == plankyBlock) { + std::cout << "adebug setSimulatorPriorityHint() '" << _entity->getName().toStdString() << "' _candidatePrioity changed from " << int(oldPriority) << " to " << int(_candidatePriority) << std::endl; // adebug + } + } } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 109c041d93..34a8c70e30 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -29,7 +29,7 @@ public: virtual ~EntityMotionState(); void updateServerPhysicsVariables(); - virtual void handleEasyChanges(uint32_t flags); + virtual void handleEasyChanges(uint32_t flags, PhysicsEngine* engine); virtual void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem @@ -68,8 +68,9 @@ public: virtual const QUuid& getObjectID() const { return _entity->getID(); } + virtual uint8_t getSimulatorPriority() const; virtual QUuid getSimulatorID() const; - virtual void bump(); + virtual void bump(uint8_t priority); EntityItemPointer getEntity() const { return _entity; } @@ -113,10 +114,11 @@ protected: float _measuredDeltaTime; quint8 _accelerationNearlyGravityCount; - bool _candidateForOwnership; - uint32_t _loopsSinceOwnershipBid; + quint64 _nextOwnershipBid = 0; uint32_t _loopsWithoutOwner; - uint8_t _simulatorPriorityHint; + uint8_t _candidatePriority = 0; + quint64 _activationTime = 0; // adebug + int _expectedOwnership = 0; // adebug }; #endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 85e67d72f7..7ff119fb79 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -114,7 +114,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -void ObjectMotionState::handleEasyChanges(uint32_t flags) { +void ObjectMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) { if (flags & EntityItem::DIRTY_POSITION) { btTransform worldTrans; if (flags & EntityItem::DIRTY_ROTATION) { @@ -159,7 +159,7 @@ void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* if ((flags & HARD_DIRTY_PHYSICS_FLAGS) == 0) { // no HARD flags remain, so do any EASY changes if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - handleEasyChanges(flags); + handleEasyChanges(flags, engine); } return; } @@ -174,7 +174,7 @@ void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* } } if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - handleEasyChanges(flags); + handleEasyChanges(flags, engine); } // it is possible that there are no HARD flags at this point (if DIRTY_SHAPE was removed) // so we check again befoe we reinsert: diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 502efb5f98..1ef3ac0dcd 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -40,7 +40,8 @@ enum MotionStateType { const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | - EntityItem::DIRTY_MATERIAL | EntityItem::DIRTY_SIMULATOR_OWNERSHIP); + EntityItem::DIRTY_MATERIAL | EntityItem::DIRTY_SIMULATOR_ID | + EntityItem::DIRTY_SIMULATOR_OWNERSHIP); // These are the set of incoming flags that the PhysicsEngine needs to hear about: const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | @@ -70,7 +71,7 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - virtual void handleEasyChanges(uint32_t flags); + virtual void handleEasyChanges(uint32_t flags, PhysicsEngine* engine); virtual void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); void updateBodyMaterialProperties(); @@ -118,8 +119,9 @@ public: virtual const QUuid& getObjectID() const = 0; + virtual uint8_t getSimulatorPriority() const { return 0; } virtual QUuid getSimulatorID() const = 0; - virtual void bump() = 0; + virtual void bump(uint8_t priority) {} virtual QString getName() { return ""; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 55fc5e6295..a200abede2 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -194,7 +194,7 @@ void PhysicsEngine::changeObjects(VectorOfMotionStates& objects) { if (flags & HARD_DIRTY_PHYSICS_FLAGS) { object->handleHardAndEasyChanges(flags, this); } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - object->handleEasyChanges(flags); + object->handleEasyChanges(flags, this); } } } @@ -260,9 +260,6 @@ void PhysicsEngine::stepSimulation() { void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) { BT_PROFILE("ownershipInfection"); - if (_sessionID.isNull()) { - return; - } const btCollisionObject* characterObject = _characterController ? _characterController->getCollisionObject() : nullptr; @@ -272,14 +269,14 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const if (b && ((a && a->getSimulatorID() == _sessionID && !objectA->isStaticObject()) || (objectA == characterObject))) { // NOTE: we might own the simulation of a kinematic object (A) // but we don't claim ownership of kinematic objects (B) based on collisions here. - if (!objectB->isStaticOrKinematicObject()) { - b->bump(); + if (!objectB->isStaticOrKinematicObject() && b->getSimulatorID() != _sessionID) { + b->bump(a->getSimulatorPriority()); } } else if (a && ((b && b->getSimulatorID() == _sessionID && !objectB->isStaticObject()) || (objectB == characterObject))) { // SIMILARLY: we might own the simulation of a kinematic object (B) // but we don't claim ownership of kinematic objects (A) based on collisions here. - if (!objectA->isStaticOrKinematicObject()) { - a->bump(); + if (!objectA->isStaticOrKinematicObject() && a->getSimulatorID() != _sessionID) { + a->bump(b->getSimulatorPriority()); } } } @@ -311,7 +308,9 @@ void PhysicsEngine::updateContactMap() { _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0)); } - doOwnershipInfection(objectA, objectB); + if (!_sessionID.isNull()) { + doOwnershipInfection(objectA, objectB); + } } } } @@ -402,7 +401,7 @@ void PhysicsEngine::bump(ObjectMotionState* motionState) { if (!objectA->isStaticOrKinematicObject()) { ObjectMotionState* motionStateA = static_cast(objectA->getUserPointer()); if (motionStateA) { - motionStateA->bump(); + motionStateA->bump(VOLUNTEER_SIMULATOR_PRIORITY); objectA->setActivationState(ACTIVE_TAG); } } @@ -410,7 +409,7 @@ void PhysicsEngine::bump(ObjectMotionState* motionState) { if (!objectB->isStaticOrKinematicObject()) { ObjectMotionState* motionStateB = static_cast(objectB->getUserPointer()); if (motionStateB) { - motionStateB->bump(); + motionStateB->bump(VOLUNTEER_SIMULATOR_PRIORITY); objectB->setActivationState(ACTIVE_TAG); } } From b6d5adaef81d18dee3ab06bdeda9ef737bd23522 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 23 Jun 2015 14:18:17 -0700 Subject: [PATCH 12/24] move global into function that uses it --- libraries/shared/src/StreamUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/StreamUtils.cpp b/libraries/shared/src/StreamUtils.cpp index b2ea5d95a4..5726728f30 100644 --- a/libraries/shared/src/StreamUtils.cpp +++ b/libraries/shared/src/StreamUtils.cpp @@ -15,9 +15,9 @@ #include "StreamUtils.h" -const char* hex_digits = "0123456789abcdef"; void StreamUtil::dump(std::ostream& s, const QByteArray& buffer) { + const char* hex_digits = "0123456789abcdef"; int row_size = 32; int i = 0; while (i < buffer.size()) { From 12fc18092bacce492be6f0eccc682900a55d6485 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 23 Jun 2015 16:19:57 -0700 Subject: [PATCH 13/24] SimulationOwner as one property --- libraries/entities/src/EntityItem.cpp | 201 ++++++------------ libraries/entities/src/EntityItem.h | 43 +--- .../entities/src/EntityItemProperties.cpp | 161 ++++---------- libraries/entities/src/EntityItemProperties.h | 13 +- libraries/entities/src/EntityPropertyFlags.h | 4 +- .../entities/src/EntityScriptingInterface.cpp | 21 +- libraries/entities/src/EntityTree.cpp | 20 +- libraries/entities/src/SimulationOwner.cpp | 188 ++++++++++++++++ libraries/entities/src/SimulationOwner.h | 78 +++++++ libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/octree/src/OctreePacketData.h | 1 + libraries/physics/src/EntityMotionState.cpp | 35 +-- 12 files changed, 435 insertions(+), 332 deletions(-) create mode 100644 libraries/entities/src/SimulationOwner.cpp create mode 100644 libraries/entities/src/SimulationOwner.h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 888ca239e2..9752c46aed 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include // adebug +#include // adebug + #include #include @@ -69,9 +72,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _collisionsWillMove(ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE), _locked(ENTITY_ITEM_DEFAULT_LOCKED), _userData(ENTITY_ITEM_DEFAULT_USER_DATA), - _simulatorPriority(0), - _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), - _simulationOwnershipExpiry(0), + _simulationOwner(), _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), _name(ENTITY_ITEM_DEFAULT_NAME), _href(""), @@ -102,6 +103,7 @@ EntityItem::~EntityItem() { EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties; + requestedProperties += PROP_SIMULATION_OWNER; requestedProperties += PROP_POSITION; requestedProperties += PROP_DIMENSIONS; // NOTE: PROP_RADIUS obsolete requestedProperties += PROP_ROTATION; @@ -126,8 +128,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_USER_DATA; requestedProperties += PROP_MARKETPLACE_ID; requestedProperties += PROP_NAME; - requestedProperties += PROP_SIMULATOR_PRIORITY; - requestedProperties += PROP_SIMULATOR_ID; requestedProperties += PROP_HREF; requestedProperties += PROP_DESCRIPTION; @@ -235,6 +235,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, + APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); APPEND_ENTITY_PROPERTY(PROP_POSITION, getPosition()); APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions()); // NOTE: PROP_RADIUS obsolete APPEND_ENTITY_PROPERTY(PROP_ROTATION, getRotation()); @@ -256,8 +257,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); - APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_PRIORITY, getSimulatorPriority()); - APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, getSimulatorID()); APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID()); APPEND_ENTITY_PROPERTY(PROP_NAME, getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL()); @@ -328,6 +327,7 @@ int EntityItem::expectedBytes() { // clients use this method to unpack FULL updates from entity-server int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { + static quint64 maxSkipTime = 0; // adebug if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { @@ -359,7 +359,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef glm::vec3 saveAngularVelocity = _angularVelocity; int originalLength = bytesLeftToRead; - QByteArray originalDataBuffer((const char*)data, originalLength); + // TODO: figure out a way to avoid the big deep copy below. + QByteArray originalDataBuffer((const char*)data, originalLength); // big deep copy! int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0; @@ -443,6 +444,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef #endif bool ignoreServerPacket = false; // assume we'll use this server packet + std::ostringstream debugOutput; // If this packet is from the same server edit as the last packet we accepted from the server // we probably want to use it. @@ -451,6 +453,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // the most recent packet from this server time if (_lastEdited > _lastEditedFromRemote) { ignoreServerPacket = true; + } else { + debugOutput << "adebug fromSameServerEdit for '" << _name.toStdString() << "' le - lefr = " << (_lastEdited - _lastEditedFromRemote) << std::flush; // adebug } } else { // If this isn't from the same sever packet, then honor our skew adjusted times... @@ -458,6 +462,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // then we will not be changing our values, instead we just read and skip the data if (_lastEdited > lastEditedFromBufferAdjusted) { ignoreServerPacket = true; + } else { + debugOutput << "adebug honor skew adjust for '" << _name.toStdString() << "' le - lefba = " << (_lastEdited - lastEditedFromBufferAdjusted) << std::flush; // adebug } } @@ -537,6 +543,35 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef EntityPropertyFlags propertyFlags = encodedPropertyFlags; dataAt += propertyFlags.getEncodedLength(); bytesRead += propertyFlags.getEncodedLength(); + + if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER) { + // NOTE: the server is authoritative for changes to simOwnerID so we always unpack this data, + // even when we would otherwise ignore the rest of the packet. That said, we assert the priority + // rules that we expect the server to be using, so it is possible that we'll sometimes ignore + // the incoming _simulatorID data (e.g. we might know something that the server does not... yet). + + // BOOKMARK TODO adebug: follow pattern where the class unpacks itself + if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { + QByteArray simOwnerData; + int bytes = OctreePacketData::unpackDataFromBytes(dataAt, simOwnerData); + SimulationOwner newSimOwner; + newSimOwner.fromByteArray(simOwnerData); + dataAt += bytes; + bytesRead += bytes; + + SimulationOwner oldOwner = _simulationOwner; // adebug + if (_simulationOwner.set(newSimOwner)) { + std::cout << "adebug something changed: owner = " << _simulationOwner << std::endl; // adebug + _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; + } + if (oldOwner != _simulationOwner) { + std::cout << "adebug ownership changed from " << oldOwner.getID().toString().toStdString() << ":" << int(oldOwner.getPriority()) << " to " + << _simulationOwner.getID().toString().toStdString() << ":" << int(_simulationOwner.getPriority()) + << std::endl; // adebug + } + } + } + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); // Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS @@ -577,89 +612,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); - if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATOR_PRIORITY) { - // NOTE: the server is authoritative for changes to _simulatorID so we always unpack this data, - // even when we would otherwise ignore the rest of the packet. That said, we assert the priority - // rules that we expect the server to be using, so it is possible that we'll sometimes ignore - // the incoming _simulatorID data (e.g. we might know something that the server does not... yet). - - int requiredProperties = 1; // adebug - uint8_t priority = 0; - if (propertyFlags.getHasProperty(PROP_SIMULATOR_PRIORITY)) { - int bytes = OctreePacketData::unpackDataFromBytes(dataAt, priority); - dataAt += bytes; - bytesRead += bytes; - requiredProperties *= 3; // adebug - } - - QUuid id; - if (propertyFlags.getHasProperty(PROP_SIMULATOR_ID)) { - int bytes = OctreePacketData::unpackDataFromBytes(dataAt, id); - dataAt += bytes; - bytesRead += bytes; - requiredProperties *= 7; - } - - // adebug - if (requiredProperties == 3) { - std::cout << "adebug split properties for '" << _name.toStdString() << "' with priority only" << std::endl; // adebug - } - else if (requiredProperties == 7) { - std::cout << "adebug split properties for '" << _name.toStdString() << "' with id only" << std::endl; // adebug - } - - // TODO: refactor simulation ownership info to be a single property - if (requiredProperties == 3*7) { - if (_simulatorID != id) { - // ownership has changed - auto nodeList = DependencyManager::get(); - if (_simulatorID == nodeList->getSessionUUID()) { - // we think we're the simulation owner but entity-server says otherwise - // we relenquish ownership only if we don't have MAX_SIMULATOR_PRIORITY - if (_simulatorPriority != MAX_SIMULATOR_PRIORITY) { - // we're losing simulation ownership - if (_name == plankyBlock2) { - std::cout << "adebug lose ownership of '" << _name.toStdString() << "' to " << id.toString().toStdString() << " with priority " << int(priority) << std::endl; // adebug - } - _simulatorID = id; - _simulatorPriority = priority; - if (! (_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID)) { - if (_name == plankyBlock2) { - std::cout << "adebug setting DIRTY_SIMULATOR_ID while losing ownership" << std::endl; // adebug - } - } - _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; - } - } else { - auto nodeList = DependencyManager::get(); - if (id == nodeList->getSessionUUID()) { - if (_name == plankyBlock2) { - std::cout << "adebug gain ownership of '" << _name.toStdString() << "' id " << id.toString().toStdString() << " with priority " << int(priority) << std::endl; // adebug - } - } - _simulatorID = id; - _simulatorPriority = priority; - if (! (_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID)) { - if (_name == plankyBlock2) { - std::cout << "adebug setting DIRTY_SIMULATOR_ID with ownership of " << _simulatorID.toString().toStdString() << std::endl; // adebug - } - } - _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; - } - } else if (priority != _simulatorPriority) { - // priority is changing but simulatorID is not. - // only accept this change if we are NOT the simulator owner, since otherwise - // we would have initiated this priority - auto nodeList = DependencyManager::get(); - if (_simulatorID != nodeList->getSessionUUID()) { - if (_name == plankyBlock2) { - std::cout << "adebug priority of '" << _name.toStdString() << "' changing from " << int(_simulatorPriority) << " to " << int(priority) << std::endl; // adebug - } - _simulatorPriority = priority; - } - } - } - } else if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { + if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION && + args.bitstreamVersion < VERSION_ENTITIES_HAVE_SIMULATION_OWNER) { // we always accept the server's notion of simulatorID, so we fake overwriteLocalData as true // before we try to READ_ENTITY_PROPERTY it bool temp = overwriteLocalData; @@ -698,13 +652,17 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // use our simulation helper routine to get a best estimate of where the entity should be. const float MIN_TIME_SKIP = 0.0f; const float MAX_TIME_SKIP = 1.0f; // in seconds + quint64 dt = now - lastSimulatedFromBufferAdjusted; + if (dt > maxSkipTime) { + maxSkipTime = dt; + std::cout << "adebug maxSkipTime = " << maxSkipTime << " for '" << _name.toStdString() << "'" << std::endl; // adebug + } float skipTimeForward = glm::clamp((float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND), MIN_TIME_SKIP, MAX_TIME_SKIP); if (skipTimeForward > 0.0f) { #ifdef WANT_DEBUG qCDebug(entities) << "skipTimeForward:" << skipTimeForward; #endif - // we want to extrapolate the motion forward to compensate for packet travel time, but // we don't want the side effect of flag setting. simulateKinematicMotion(skipTimeForward, false); @@ -714,7 +672,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); if (overwriteLocalData) { - if (_simulatorID == myNodeID && !_simulatorID.isNull()) { + // TODO adebug: make this use operator==() + if (_simulationOwner.matchesID(myNodeID)) { // we own the simulation, so we keep our transform+velocities and remove any related dirty flags // rather than accept the values in the packet setPosition(savePosition); @@ -723,6 +682,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _angularVelocity = saveAngularVelocity; _dirtyFlags &= ~(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES); } else { + std::cout << "adebug myNode = " << myNodeID.toString().toStdString() << " owner = " << _simulationOwner.getID().toString().toStdString() << std::endl; // adebug + std::cout << debugOutput.str() << std::endl; // adebug _lastSimulated = now; } } @@ -987,6 +948,7 @@ EntityItemProperties EntityItem::getProperties() const { properties._type = getType(); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getPosition); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getRotation); @@ -1012,8 +974,6 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulatorPriority, getSimulatorPriority); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulatorID, getSimulatorID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName); COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); @@ -1064,8 +1024,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorPriority, setSimulatorPriority); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorID, updateSimulatorID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); // non-simulation properties below SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); @@ -1443,47 +1402,21 @@ void EntityItem::updateCreated(uint64_t value) { } } -void EntityItem::setSimulatorPriority(uint8_t priority) { - if (_name == plankyBlock2) { - std::cout << "adebug setSimulatorPriority() for '" << _name.toStdString() << "' from " << int(_simulatorPriority) << " to " << int(priority) << std::endl; // adebug - } - _simulatorPriority = priority; - if (_simulatorPriority == MAX_SIMULATOR_PRIORITY) { - // we always extend the the ownership expiry for MAX_SIMULATOR_PRIORITY - _simulationOwnershipExpiry = usecTimestampNow() + MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD; - } else if (_simulatorPriority == 0) { - _simulationOwnershipExpiry = 0; - } +void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) { + _simulationOwner.set(id, priority); } -void EntityItem::setSimulatorID(const QUuid& value) { - if (_simulatorID != value) { - if (_name == plankyBlock2) { - std::cout << "adebug setSimulatorID for '" << _name.toStdString() << "' from " << _simulatorID.toString().toStdString() << " to " << value.toString().toStdString() << std::endl; // adebug - } - _simulatorID = value; - if (!_simulatorID.isNull()) { - // Note: this logic only works well if _simulatorPriority is properly set before this point - quint64 lockoutPeriod = (_simulatorPriority == MAX_SIMULATOR_PRIORITY) - ? MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD : DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD; - _simulationOwnershipExpiry = usecTimestampNow() + lockoutPeriod; - } - } +void EntityItem::setSimulationOwner(const SimulationOwner& owner) { + _simulationOwner.set(owner); } void EntityItem::updateSimulatorID(const QUuid& value) { - if (_simulatorID != value) { - if (_name == plankyBlock2) { - std::cout << "adebug updateSimulatorID for '" << _name.toStdString() << "' from " << _simulatorID.toString().toStdString() << " to " << value.toString().toStdString() << std::endl; // adebug - } - _simulatorID = value; - if (!_simulatorID.isNull()) { - // Note: this logic only works well if _simulatorPriority is properly set before this point - quint64 lockoutPeriod = (_simulatorPriority == MAX_SIMULATOR_PRIORITY) - ? MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD : DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD; - _simulationOwnershipExpiry = usecTimestampNow() + lockoutPeriod; - } + QUuid oldID = _simulationOwner.getID(); + if (_simulationOwner.setID(value)) { _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; + if (oldID != _simulationOwner.getID() && _name == plankyBlock2) { + std::cout << "adebug updateSimulatorID for '" << _name.toStdString() << "' from " << oldID.toString().toStdString() << " to " << value.toString().toStdString() << std::endl; // adebug + } } } @@ -1491,9 +1424,7 @@ void EntityItem::clearSimulationOwnership() { if (_name == plankyBlock2) { std::cout << "adebug clearSimulationOwnership for '" << _name.toStdString() << "'" << std::endl; // adebug } - _simulatorPriority = 0; - _simulatorID = QUuid(); - _simulationOwnershipExpiry = 0; + _simulationOwner.clear(); // don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulatorOwnership() // is only ever called entity-server-side and the flags are only used client-side //_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 2c62588913..f657a746d8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -29,6 +29,7 @@ #include "EntityItemProperties.h" #include "EntityItemPropertiesDefaults.h" #include "EntityTypes.h" +#include "SimulationOwner.h" class EntitySimulation; class EntityTreeElement; @@ -60,11 +61,6 @@ const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; const float ACTIVATION_GRAVITY_DELTA = 0.1f; const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; -const uint8_t VOLUNTEER_SIMULATOR_PRIORITY = 0x01; -const uint8_t SCRIPT_EDIT_SIMULATOR_PRIORITY = 0x80; -const uint8_t MAX_SIMULATOR_PRIORITY = 0xff; -const uint8_t ATTACHMENT_SIMULATOR_PRIORITY = MAX_SIMULATOR_PRIORITY; - #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; @@ -72,29 +68,6 @@ const uint8_t ATTACHMENT_SIMULATOR_PRIORITY = MAX_SIMULATOR_PRIORITY; #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) #define debugTreeVector(V) V << "[" << V << " in meters ]" -class SimulationOwner { -public: - SimulationOwner() : _id(), _priority(0) {} - SimulationOwner(const QUuid& id, uint8_t priority) : _id(id), _priority(priority) {} - - const QUuid& getID() const { return _id; } - uint8_t getPriority() const { return _priority; } - - void clear() { _id = QUuid(); _priority = 0; } - void set(const QUuid& id, uint8_t priority) { _id = id; _priority = priority; } - - bool isNull() const { return _id.isNull(); } - bool matchesID(const QUuid& id) const { return _id == id; } - //void toQByteArray(); - - bool operator>=(uint8_t priority) const { return _priority >= priority; } - -private: - QUuid _id; - uint8_t _priority; -}; - - /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. @@ -345,13 +318,13 @@ public: const QString& getUserData() const { return _userData; } void setUserData(const QString& value) { _userData = value; } - void setSimulatorPriority(uint8_t priority); - uint8_t getSimulatorPriority() const { return _simulatorPriority; } + const SimulationOwner& getSimulationOwner() const { return _simulationOwner; } + void setSimulationOwner(const QUuid& id, quint8 priority); + void setSimulationOwner(const SimulationOwner& owner); - QUuid getSimulatorID() const { return _simulatorID; } - void setSimulatorID(const QUuid& value); + quint8 getSimulatorPriority() const { return _simulationOwner.getPriority(); } + QUuid getSimulatorID() const { return _simulationOwner.getID(); } void updateSimulatorID(const QUuid& value); - const quint64& getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } void clearSimulationOwnership(); const QString& getMarketplaceID() const { return _marketplaceID; } @@ -460,9 +433,7 @@ protected: bool _collisionsWillMove; bool _locked; QString _userData; - uint8_t _simulatorPriority; - QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity - quint64 _simulationOwnershipExpiry; // time in future when ownership is back up for grabs + SimulationOwner _simulationOwner; QString _marketplaceID; QString _name; QString _href; //Hyperlink href diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8d9b703874..9979caa9df 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -17,6 +17,7 @@ #include #include #include +#include // adebug #include "EntitiesLogging.h" #include "EntityItem.h" @@ -38,7 +39,7 @@ EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE), -CONSTRUCT_PROPERTY(position, 0), +CONSTRUCT_PROPERTY(position, 0.0f), CONSTRUCT_PROPERTY(dimensions, ENTITY_ITEM_DEFAULT_DIMENSIONS), CONSTRUCT_PROPERTY(rotation, ENTITY_ITEM_DEFAULT_ROTATION), CONSTRUCT_PROPERTY(density, ENTITY_ITEM_DEFAULT_DENSITY), @@ -73,8 +74,7 @@ CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED), CONSTRUCT_PROPERTY(textures, ""), CONSTRUCT_PROPERTY(animationSettings, ""), CONSTRUCT_PROPERTY(userData, ENTITY_ITEM_DEFAULT_USER_DATA), -CONSTRUCT_PROPERTY(simulatorPriority, 0), -CONSTRUCT_PROPERTY(simulatorID, ENTITY_ITEM_DEFAULT_SIMULATOR_ID), +CONSTRUCT_PROPERTY(simulationOwner, SimulationOwner()), CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT), CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT), CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR), @@ -290,8 +290,8 @@ void EntityItemProperties::setBackgroundModeFromString(const QString& background EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; - CHECK_PROPERTY_CHANGE(PROP_DIMENSIONS, dimensions); CHECK_PROPERTY_CHANGE(PROP_POSITION, position); + CHECK_PROPERTY_CHANGE(PROP_DIMENSIONS, dimensions); CHECK_PROPERTY_CHANGE(PROP_ROTATION, rotation); CHECK_PROPERTY_CHANGE(PROP_DENSITY, density); CHECK_PROPERTY_CHANGE(PROP_VELOCITY, velocity); @@ -325,9 +325,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked); CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures); CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData); - // TODO: combine these as one property - CHECK_PROPERTY_CHANGE(PROP_SIMULATOR_PRIORITY, simulatorPriority); - CHECK_PROPERTY_CHANGE(PROP_SIMULATOR_ID, simulatorID); + CHECK_PROPERTY_CHANGE(PROP_SIMULATION_OWNER, simulationOwner); CHECK_PROPERTY_CHANGE(PROP_TEXT, text); CHECK_PROPERTY_CHANGE(PROP_LINE_HEIGHT, lineHeight); CHECK_PROPERTY_CHANGE(PROP_TEXT_COLOR, textColor); @@ -422,8 +420,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(locked); COPY_PROPERTY_TO_QSCRIPTVALUE(textures); COPY_PROPERTY_TO_QSCRIPTVALUE(userData); - COPY_PROPERTY_TO_QSCRIPTVALUE(simulatorPriority); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(simulatorID, getSimulatorIDAsString()); + //COPY_PROPERTY_TO_QSCRIPTVALUE(simulationOwner); // TODO: expose this for JSON saves? COPY_PROPERTY_TO_QSCRIPTVALUE(text); COPY_PROPERTY_TO_QSCRIPTVALUE(lineHeight); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(textColor, getTextColor()); @@ -574,8 +571,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec return result; }); - COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorPriority, float, setSimulatorPriority); - COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); + // TODO: expose this to QScriptValue for JSON saves? + //COPY_PROPERTY_FROM_QSCRIPTVALUE(simulationOwner, ???, setSimulatorPriority); } _stage.copyFromScriptValue(object, _defaultSettings); @@ -710,41 +707,26 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, -/* TODO: remove this old experiment code - // simulation ownership data needs to get back ASAP, and affects whether the "terse update" - // data will be accepted at the receiving end, so we put it at the front. -// if (requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY) && -// requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { -// QByteArray ownershipData = properties.getSimulatorID().toRfc4122(); -// ownershipData.append(properties.getSimulatorPriority(); -// LevelDetails propertyLevel = packetData->startLevel(); -// if (packetData->appendRawData(ownershipData)) { -// propertyFlags |= PROP_SIMULATOR_PRIORITY; -// propertiesDidntFit -= PROP_SIMULATOR_PRIORITY; -// propertyCount++; -// -// propertyFlags |= PROP_SIMULATOR_ID; -// propertiesDidntFit -= PROP_SIMULATOR_ID; -// propertyCount++; -// -// packetData->endLevel(propertyLevel); -// } -// } - // BOOKMARK -- replace the two ownership properties with one... at the EntityProperties level - // but make it two properties at the EntityItem - if (requestedProperties.getHasProperty(PROP_SIMULATOR_OWNERSHIP)) { - QByteArray ownershipData = properties.getSimulatorID().toRfc4122(); - ownershipData.append(properties.getSimulatorPriority(); + // adebug TODO: convert this to use APPEND_ENTITY_PROPERTY(P,V) macro? + if (requestedProperties.getHasProperty(PROP_SIMULATION_OWNER)) { LevelDetails propertyLevel = packetData->startLevel(); - if (packetData->appendRawData(ownershipData)) { - propertyFlags |= PROP_SIMULATOR_OWNERSHIP; + successPropertyFits = packetData->appendValue(properties._simulationOwner.toByteArray()); + if (successPropertyFits) { +// std::cout << "adebug appending ownerhip data" << std::endl; // adebug +// StreamUtil::dump(std::cout, properties._simulationOwner.toByteArray()); + propertyFlags |= PROP_SIMULATION_OWNER; + propertiesDidntFit -= PROP_SIMULATION_OWNER; propertyCount++; packetData->endLevel(propertyLevel); } else { - propertiesDidntFit -= PROP_SIMULATOR_OWNERSHIP; +// std::cout << "adebug ownership data did not fit" << std::endl; // adebug + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; } + } else { +// std::cout << "adebug property doesn't have ownerhip data" << std::endl; // adebug + propertiesDidntFit -= PROP_SIMULATION_OWNER; } - */ APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition()); APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete @@ -768,66 +750,6 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, properties.getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); - APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_PRIORITY, properties.getSimulatorPriority()); - APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, properties.getSimulatorID()); -/* TODO remove this experiment too - if (requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY) && - requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { - - QByteArray bytes = properties.getSimulatorID().toRfc4122(); - if (packetData->canAppendBytes(1 + bytes.size())) { - APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_PRIORITY, properties.getSimulatorPriority()); - APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, properties.getSimulatorID()); - } else { - LevelDetails propertyLevel = packetData->startLevel(); - successPropertyFits = false; - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; - } - } - if (!requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY)) { - propertiesDidntFit -= PROP_SIMULATOR_PRIORITY; - } - if (!requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { - propertiesDidntFit -= PROP_SIMULATOR_ID; - } - } -*/ -/* and this one - //#define APPEND_ENTITY_PROPERTY(P,V) - if (requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY) && - requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { - - LevelDetails propertyLevel = packetData->startLevel(); - - QByteArray bytes = properties.getSimulatorID().toRfc4122(); - if (packetData->canAppendBytes(10 + bytes.size())) { - packetData->appendValue(properties.getSimulatorPriority()); - propertyFlags |= PROP_SIMULATOR_PRIORITY; - propertiesDidntFit -= PROP_SIMULATOR_PRIORITY; - propertyCount++; - packetData->endLevel(propertyLevel); - - propertyLevel = packetData->startLevel(); - packetData->appendValue(properties.getSimulatorID()); - propertyFlags |= PROP_SIMULATOR_ID; - propertiesDidntFit -= PROP_SIMULATOR_ID; - propertyCount++; - packetData->endLevel(propertyLevel); - } else { - successPropertyFits = false; - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; - } - } else { - if (!requestedProperties.getHasProperty(PROP_SIMULATOR_PRIORITY)) { - propertiesDidntFit -= PROP_SIMULATOR_PRIORITY; - } - if (!requestedProperties.getHasProperty(PROP_SIMULATOR_ID)) { - propertiesDidntFit -= PROP_SIMULATOR_ID; - } - } -*/ APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); @@ -1059,7 +981,23 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int EntityPropertyFlags propertyFlags = encodedPropertyFlags; dataAt += propertyFlags.getEncodedLength(); processedBytes += propertyFlags.getEncodedLength(); - + + // adebug TODO: convert this to use READ_ENTITY_PROPERTY_TO_PROPERTIES macro? + if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { + QByteArray fromBuffer; + int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); + + dataAt += bytes; + processedBytes += bytes; + SimulationOwner simOwner; + simOwner.fromByteArray(fromBuffer); + properties.setSimulationOwner(simOwner); +// std::cout << "adebug decoding ownerhip data" << std::endl; // adebug +// StreamUtil::dump(std::cout, fromBuffer); + } else { +// std::cout << "adebug no ownership info to decode" << std::endl; // adebug + } + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATION, glm::quat, setRotation); @@ -1082,8 +1020,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATOR_PRIORITY, uint8_t, setSimulatorPriority); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATOR_ID, QUuid, setSimulatorID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription); @@ -1199,6 +1135,7 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt } void EntityItemProperties::markAllChanged() { + _simulationOwnerChanged = true; _positionChanged = true; _dimensionsChanged = true; _rotationChanged = true; @@ -1211,8 +1148,6 @@ void EntityItemProperties::markAllChanged() { _frictionChanged = true; _lifetimeChanged = true; _userDataChanged = true; - _simulatorPriorityChanged = true; - _simulatorIDChanged = true; _scriptChanged = true; _scriptTimestampChanged = true; _collisionSoundURLChanged = true; @@ -1336,16 +1271,12 @@ bool EntityItemProperties::hasMiscPhysicsChanges() const { _compoundShapeURLChanged || _collisionsWillMoveChanged || _ignoreForCollisionsChanged; } -void EntityItemProperties::clearSimulatorOwnership() { - _simulatorID = QUuid(); - _simulatorPriority = 0; - _simulatorIDChanged = true; - _simulatorPriorityChanged = true; +void EntityItemProperties::clearSimulationOwner() { + _simulationOwner.clear(); + _simulationOwnerChanged = true; } -void EntityItemProperties::setSimulatorOwnership(const QUuid& id, uint8_t priority) { - _simulatorID = id; - _simulatorPriority = glm::max(priority, _simulatorPriority); - _simulatorIDChanged = true; - _simulatorPriorityChanged = true; +void EntityItemProperties::setSimulationOwner(const QUuid& id, uint8_t priority) { + _simulationOwner.set(id, priority); + _simulationOwnerChanged = true; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 4210b342f2..f84e897331 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -34,6 +34,7 @@ #include "EntityItemPropertiesMacros.h" #include "EntityTypes.h" #include "EntityPropertyFlags.h" +#include "SimulationOwner.h" #include "SkyboxPropertyGroup.h" #include "StagePropertyGroup.h" @@ -120,8 +121,7 @@ public: DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString); DEFINE_PROPERTY_REF_WITH_SETTER_AND_GETTER(PROP_ANIMATION_SETTINGS, AnimationSettings, animationSettings, QString); DEFINE_PROPERTY_REF(PROP_USER_DATA, UserData, userData, QString); - DEFINE_PROPERTY(PROP_SIMULATOR_PRIORITY, SimulatorPriority, simulatorPriority, uint8_t); - DEFINE_PROPERTY_REF(PROP_SIMULATOR_ID, SimulatorID, simulatorID, QUuid); + DEFINE_PROPERTY_REF(PROP_SIMULATION_OWNER, SimulationOwner, simulationOwner, SimulationOwner); DEFINE_PROPERTY_REF(PROP_TEXT, Text, text, QString); DEFINE_PROPERTY(PROP_LINE_HEIGHT, LineHeight, lineHeight, float); DEFINE_PROPERTY_REF(PROP_TEXT_COLOR, TextColor, textColor, xColor); @@ -197,7 +197,7 @@ public: const QStringList& getTextureNames() const { return _textureNames; } void setTextureNames(const QStringList& value) { _textureNames = value; } - QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); } + QString getSimulatorIDAsString() const { return _simulationOwner.getID().toString().mid(1,36).toUpper(); } void setVoxelDataDirty() { _voxelDataChanged = true; } @@ -208,8 +208,8 @@ public: bool hasTerseUpdateChanges() const; bool hasMiscPhysicsChanges() const; - void clearSimulatorOwnership(); - void setSimulatorOwnership(const QUuid& id, uint8_t priority); + void clearSimulationOwner(); + void setSimulationOwner(const QUuid& id, uint8_t priority); private: QUuid _id; @@ -289,8 +289,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Locked, locked, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Textures, textures, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, UserData, userData, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulatorPriority, simulatorPriority, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulatorID, simulatorID, QUuid()); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulationOwner, simulationOwner, SimulationOwner()); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Text, text, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LineHeight, lineHeight, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, TextColor, textColor, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 08569adaf4..163870c225 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -104,7 +104,7 @@ enum EntityPropertyList { PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities PROP_MARKETPLACE_ID, // all entities PROP_ACCELERATION, // all entities - PROP_SIMULATOR_ID, // all entities + PROP_SIMULATOR_ID, // unused PROP_NAME, // all entities PROP_COLLISION_SOUND_URL, PROP_RESTITUTION, @@ -121,7 +121,7 @@ enum EntityPropertyList { // used by hyperlinks PROP_HREF, PROP_DESCRIPTION, - PROP_SIMULATOR_PRIORITY, + PROP_SIMULATION_OWNER, PROP_FACE_CAMERA, PROP_SCRIPT_TIMESTAMP, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6786763a83..0693c1e85c 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -9,18 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include // adebug +#include "EntityScriptingInterface.h" + #include +#include "EntitiesLogging.h" +#include "EntityActionFactoryInterface.h" +#include "EntityActionInterface.h" +#include "EntitySimulation.h" #include "EntityTree.h" #include "LightEntityItem.h" #include "ModelEntityItem.h" +#include "SimulationOwner.h" #include "ZoneEntityItem.h" -#include "EntitiesLogging.h" -#include "EntitySimulation.h" -#include "EntityActionInterface.h" -#include "EntityActionFactoryInterface.h" -#include "EntityScriptingInterface.h" EntityScriptingInterface::EntityScriptingInterface() : _entityTree(NULL) @@ -76,10 +79,10 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties // This Node is creating a new object. If it's in motion, set this Node as the simulator. auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); - propertiesWithSimID.setSimulatorOwnership(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); + propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); // and make note of it now, so we can act on it right away. - entity->setSimulatorID(propertiesWithSimID.getSimulatorID()); + entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); entity->setLastBroadcast(usecTimestampNow()); } else { @@ -160,11 +163,11 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper // simulation. // we re-assert our simulation ownership - properties.setSimulatorOwnership(myNodeID, + properties.setSimulationOwner(myNodeID, glm::max(entity->getSimulatorPriority(), SCRIPT_EDIT_SIMULATOR_PRIORITY)); } else { // we make a bid for simulation ownership - properties.setSimulatorOwnership(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); + properties.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); entity->flagForOwnership(); } } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 4a03b0a6df..45b5a95271 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -150,14 +150,14 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI } else { if (getIsServer()) { bool simulationBlocked = !entity->getSimulatorID().isNull(); - if (properties.simulatorIDChanged()) { - QUuid submittedID = properties.getSimulatorID(); + if (properties.simulationOwnerChanged()) { + QUuid submittedID = properties.getSimulationOwner().getID(); // a legit interface will only submit their own ID or NULL: if (submittedID.isNull()) { if (entity->getSimulatorID() == senderID) { // We only allow the simulation owner to clear their own simulationID's. simulationBlocked = false; - properties.setSimulatorPriority(0); // clear priority irregardless of priority sent + properties.clearSimulationOwner(); // clear everything } // else: We assume the sender really did believe it was the simulation owner when it sent } else if (submittedID == senderID) { @@ -170,10 +170,9 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI // (1) higher priority wins // (2) equal priority wins if ownership filter has expired except... uint8_t oldPriority = entity->getSimulatorPriority(); - uint8_t newPriority = properties.getSimulatorPriority(); + uint8_t newPriority = properties.getSimulationOwner().getPriority(); if (newPriority > oldPriority || - (newPriority == oldPriority && - usecTimestampNow() > entity->getSimulationOwnershipExpiry())) { + (newPriority == oldPriority && properties.getSimulationOwner().hasExpired())) { simulationBlocked = false; } } @@ -183,11 +182,13 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI } } if (simulationBlocked) { - // squash the physics-related changes. - properties.setSimulatorPriorityChanged(false); - properties.setSimulatorIDChanged(false); + // squash ownership and physics-related changes. + properties.setSimulationOwnerChanged(false); properties.setPositionChanged(false); properties.setRotationChanged(false); + properties.setVelocityChanged(false); + properties.setAngularVelocityChanged(false); + properties.setAccelerationChanged(false); } } // else client accepts what the server says @@ -203,7 +204,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI uint32_t newFlags = entity->getDirtyFlags() & ~preFlags; if (newFlags) { if (_simulation) { - std::cout << "adebug newFlags & DIRTY_SIMULATION_FLAGS = 0x" << std::hex << (newFlags & DIRTY_SIMULATION_FLAGS) << std::dec << std::endl; // adebug if (newFlags & DIRTY_SIMULATION_FLAGS) { _simulation->lock(); _simulation->changeEntity(entity); diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp new file mode 100644 index 0000000000..f858665260 --- /dev/null +++ b/libraries/entities/src/SimulationOwner.cpp @@ -0,0 +1,188 @@ +// +// SimulationOwner.cpp +// libraries/entities/src +// +// Created by Andrew Meadows on 2015.06.19 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "SimulationOwner.h" + +#include + +#include + +// static +const int SimulationOwner::NUM_BYTES_ENCODED = NUM_BYTES_RFC4122_UUID + 1; + + +SimulationOwner::SimulationOwner(const SimulationOwner& other) + : _id(other._id), _priority(other._priority), _expiry(other._expiry) { +} + +QByteArray SimulationOwner::toByteArray() const { + QByteArray data = _id.toRfc4122(); + data.append(_priority); + return data; +} + +bool SimulationOwner::fromByteArray(const QByteArray& data) { + if (data.size() == NUM_BYTES_ENCODED) { + QByteArray idBytes = data.left(NUM_BYTES_RFC4122_UUID); + _id = QUuid::fromRfc4122(idBytes); + _priority = data[NUM_BYTES_RFC4122_UUID]; + return true; + } + return false; +} + +void SimulationOwner::clear() { + _id = QUuid(); + _priority = 0; + _expiry = 0; +} + +void SimulationOwner::setPriority(quint8 priority) { + _priority = priority; + if (_priority == MAX_SIMULATOR_PRIORITY) { + // we extend the the expiry whenever we set MAX_SIMULATOR_PRIORITY + updateExpiry(); + } else if (_priority == 0) { + // when priority is zero we clear everything + _expiry = 0; + _id = QUuid(); + } +} + +bool SimulationOwner::setID(const QUuid& id) { + if (_id != id) { + _id = id; + updateExpiry(); + if (_id.isNull()) { + // when id is null we clear everything + _priority = 0; + _expiry = 0; + } + return true; + } + return false; +} + +bool SimulationOwner::set(const QUuid& id, quint8 priority) { + setPriority(priority); + return setID(id); +} + +bool SimulationOwner::set(const SimulationOwner& owner) { + setPriority(owner._priority); + return setID(owner._id); +} + +void SimulationOwner::updateExpiry() { + const quint64 OWNERSHIP_LOCKOUT_EXPIRY = USECS_PER_SECOND / 5; + _expiry = usecTimestampNow() + OWNERSHIP_LOCKOUT_EXPIRY; +} + +// TODO: move this test code out +// static debug +void SimulationOwner::test() { + { // test default constructor + SimulationOwner simOwner; + if (!simOwner.isNull()) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : SimulationOwner should be NULL" << std::endl; + } + + if (simOwner.getPriority() != 0) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : unexpeced SimulationOwner priority" << std::endl; + } + } + + { // test set constructor + QUuid id = QUuid::createUuid(); + quint8 priority = 128; + SimulationOwner simOwner(id, priority); + if (simOwner.isNull()) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : SimulationOwner should NOT be NULL" << std::endl; + } + + if (simOwner.getID() != id) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : SimulationOwner with unexpected id" << std::endl; + } + + if (simOwner.getPriority() != priority) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : unexpeced SimulationOwner priority" << std::endl; + } + + QUuid otherID = QUuid::createUuid(); + if (simOwner.getID() == otherID) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : SimulationOwner with unexpected id" << std::endl; + } + } + + { // test set() + QUuid id = QUuid::createUuid(); + quint8 priority = 1; + SimulationOwner simOwner; + simOwner.set(id, priority); + if (simOwner.isNull()) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : SimulationOwner should NOT be NULL" << std::endl; + } + + if (simOwner.getID() != id) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : SimulationOwner with unexpected id" << std::endl; + } + + if (simOwner.getPriority() != priority) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : unexpeced SimulationOwner priority" << std::endl; + } + } + + { // test encode/decode + SimulationOwner ownerA(QUuid::createUuid(), 1); + SimulationOwner ownerB(QUuid::createUuid(), 2); + + QByteArray data = ownerA.toByteArray(); + ownerB.fromByteArray(data); + + if (ownerA.getID() != ownerB.getID()) { + std::cout << __FILE__ << ":" << __LINE__ << " ERROR : ownerA._id should be equal to ownerB._id" << std::endl; + } + } +} + +bool SimulationOwner::operator==(const SimulationOwner& other) { + return (_id == other._id && _priority == other._priority); +} + +bool SimulationOwner::operator!=(const SimulationOwner& other) { + return (_id != other._id && _priority != other._priority); +} + +SimulationOwner& SimulationOwner::operator=(const SimulationOwner& other) { + _priority = other._priority; + if (_priority == 0) { + _id = QUuid(); + _expiry = 0; + } else { + if (_id != other._id) { + updateExpiry(); + } + _id = other._id; + } + return *this; +} + +// friend of SimulationOwner +std::ostream& operator<<(std::ostream& s, const SimulationOwner& simOwner) { + s << "{ id : " << simOwner._id.toString().toStdString() << ", priority : " << (int)simOwner._priority << " }"; + return s; +} + +QDebug& operator<<(QDebug& d, const SimulationOwner& simOwner) { + d << "{ id : " << simOwner << ", priority : " << (int)simOwner._priority << " }"; + return d; +} + diff --git a/libraries/entities/src/SimulationOwner.h b/libraries/entities/src/SimulationOwner.h new file mode 100644 index 0000000000..449bf85f7a --- /dev/null +++ b/libraries/entities/src/SimulationOwner.h @@ -0,0 +1,78 @@ +// +// SimulationOwner.h +// libraries/entities/src +// +// Created by Andrew Meadows on 2015.06.19 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_SimulationOwner_h +#define hifi_SimulationOwner_h + +#include + +#include +#include + +#include +#include + +const quint8 VOLUNTEER_SIMULATOR_PRIORITY = 0x01; +const quint8 SCRIPT_EDIT_SIMULATOR_PRIORITY = 0x80; +const quint8 MAX_SIMULATOR_PRIORITY = 0xff; +const quint8 ATTACHMENT_SIMULATOR_PRIORITY = MAX_SIMULATOR_PRIORITY; + +class SimulationOwner { +public: + static const int NUM_BYTES_ENCODED; + + SimulationOwner() : _id(), _priority(0), _expiry(0) {} + SimulationOwner(const QUuid& id, quint8 priority) : _id(id), _priority(priority), _expiry(0) {} + SimulationOwner(const SimulationOwner& other); + + const QUuid& getID() const { return _id; } + quint8 getPriority() const { return _priority; } + const quint64& getExpiry() const { return _expiry; } + + QByteArray toByteArray() const; + bool fromByteArray(const QByteArray& data); + + void clear(); + + void setPriority(quint8 priority); + + // return true if id is changed + bool setID(const QUuid& id); + bool set(const QUuid& id, quint8 priority); + bool set(const SimulationOwner& owner); + + bool isNull() const { return _id.isNull(); } + bool matchesID(const QUuid& id) const { return _id == id && !_id.isNull(); } + + void updateExpiry(); + + bool hasExpired() const { return usecTimestampNow() > _expiry; } + + bool operator>=(quint8 priority) const { return _priority >= priority; } + bool operator==(const SimulationOwner& other); + bool operator!=(const SimulationOwner& other); + SimulationOwner& operator=(const SimulationOwner& other); + + friend std::ostream& operator<<(std::ostream& s, const SimulationOwner& simOwner); + friend QDebug& operator<<(QDebug& d, const SimulationOwner& simOwner); + + // debug + static void test(); + +private: + QUuid _id; + quint8 _priority; + quint64 _expiry; +}; + + + +#endif // hifi_SimulationOwner_h diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 1c14c3dbde..1a579cb6c9 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -73,7 +73,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketTypeEntityAdd: case PacketTypeEntityEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_HAVE_SIMULATOR_PRIORITY; + return VERSION_ENTITIES_HAVE_SIMULATION_OWNER; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 1dc66b23ca..20d3db72c8 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -249,6 +249,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result); + QByteArray getRawData() const { return QByteArray((const char*)_uncompressed, _bytesInUse); } // adebug private: /// appends raw bytes, might fail if byte would cause packet to be too large diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f2f5991124..64b0c317bd 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -22,7 +22,8 @@ #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS #include "EntityTree.h" #endif -const char* plankyBlock = "PlankyBlock46"; // adebug +//const char* plankyBlock = "PlankyBlock46"; // adebug +const char* plankyBlock = "magenta"; // adebug static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; @@ -97,17 +98,17 @@ void EntityMotionState::updateServerPhysicsVariables() { // virtual void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) { assert(entityTreeIsLocked()); - if (_entity && _entity->getName() == plankyBlock) { - quint64 dt = (usecTimestampNow() - _activationTime) / 1000; // adebug - std::cout << "adebug handleEasyChanges flags = 0x" << std::hex << flags << std::dec << " dt = " << dt << std::endl; // adebug - } +// if (_entity && _entity->getName() == plankyBlock) { +// quint64 dt = (usecTimestampNow() - _activationTime) / 1000; // adebug +// std::cout << "adebug handleEasyChanges flags = 0x" << std::hex << flags << std::dec << " dt = " << dt << std::endl; // adebug +// } updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags, engine); if (flags & EntityItem::DIRTY_SIMULATOR_ID) { - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' found DIRTY_SIMULATOR_ID flag" << std::endl; // adebug - } +// if (_entity && _entity->getName() == plankyBlock) { +// std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' found DIRTY_SIMULATOR_ID flag" << std::endl; // adebug +// } _loopsWithoutOwner = 0; if (_entity->getSimulatorID().isNull()) { // simulation ownership is being removed @@ -116,9 +117,9 @@ void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) flags &= ~EntityItem::DIRTY_PHYSICS_ACTIVATION; // hint to Bullet that the object is deactivating _body->setActivationState(WANTS_DEACTIVATION); - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' clearing ownership so _candidatePriority goes to 0" << std::endl; // adebug - } +// if (_entity && _entity->getName() == plankyBlock) { +// std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' clearing ownership so _candidatePriority goes to 0" << std::endl; // adebug +// } _candidatePriority = 0; if (_expectedOwnership != -1) { std::cout << "adebug unexpected loss of ownership '" << _entity->getName().toStdString() << "' expected -1 but got " << _expectedOwnership << std::endl; // adebug @@ -128,9 +129,9 @@ void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulatorPriority() > _candidatePriority) { // we own the simulation or our priority looses to remote - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' we own it so _candidatePriority goes to 0" << std::endl; // adebug - } +// if (_entity && _entity->getName() == plankyBlock) { +// std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' we own it so _candidatePriority goes to 0" << std::endl; // adebug +// } if (_expectedOwnership != 1) { std::cout << "adebug unexpected gain of ownership '" << _entity->getName().toStdString() << "' expected 1 but got " << _expectedOwnership << " _candidatePriority = " << int(_candidatePriority) << std::endl; // adebug } @@ -478,14 +479,14 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID // but we remember that we do still own it... and rely on the server to tell us that we don't std::cout << "adebug releasing ownership of '" << _entity->getName().toStdString() << "' for inactivity" << std::endl; // adebug - properties.clearSimulatorOwnership(); + properties.clearSimulationOwner(); if (_entity && _entity->getName() == plankyBlock) { std::cout << "adebug sendUpdate() send clear ownership for '" << _entity->getName().toStdString() << "'" << std::endl; // adebug } _expectedOwnership = -1; } else { // re-assert the simulation info - properties.setSimulatorOwnership(sessionID, _entity->getSimulatorPriority()); + properties.setSimulationOwner(sessionID, _entity->getSimulatorPriority()); _expectedOwnership = 0; } } else { @@ -495,7 +496,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q if (_entity && _entity->getName() == plankyBlock) { std::cout << "adebug sendUpdate() bid for ownership of '" << _entity->getName().toStdString() << "' dt = " << dt << " with priority " << int(bidPriority) << std::endl; // adebug } - properties.setSimulatorOwnership(sessionID, glm::max(_candidatePriority, VOLUNTEER_SIMULATOR_PRIORITY)); + properties.setSimulationOwner(sessionID, glm::max(_candidatePriority, VOLUNTEER_SIMULATOR_PRIORITY)); _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; _expectedOwnership = 1; //_candidatePriority = 0; // TODO: it would be nice to not have to clear this until we get a message back that ownership has changed From 44d3074561271f38eb7f84654027b940137bceb6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Jun 2015 10:22:13 -0700 Subject: [PATCH 14/24] remove debug code --- libraries/entities/src/EntityItem.cpp | 46 +---------- libraries/entities/src/EntityItem.h | 3 +- .../entities/src/EntityItemProperties.cpp | 9 --- .../entities/src/EntityScriptingInterface.cpp | 1 - libraries/entities/src/SimulationOwner.cpp | 13 +-- libraries/entities/src/SimulationOwner.h | 8 +- libraries/physics/src/EntityMotionState.cpp | 79 +++---------------- libraries/physics/src/EntityMotionState.h | 6 +- 8 files changed, 24 insertions(+), 141 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9752c46aed..60d7c5a4d1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -9,8 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include // adebug -#include // adebug +#include "EntityItem.h" #include @@ -25,12 +24,10 @@ #include #include "EntityScriptingInterface.h" -#include "EntityItem.h" #include "EntitiesLogging.h" #include "EntityTree.h" #include "EntitySimulation.h" -const char* plankyBlock2 = "PlankyBlock46"; // adebug const quint64 DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND); const quint64 MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD = 2 * USECS_PER_SECOND; @@ -327,8 +324,6 @@ int EntityItem::expectedBytes() { // clients use this method to unpack FULL updates from entity-server int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - static quint64 maxSkipTime = 0; // adebug - if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { // NOTE: This shouldn't happen. The only versions of the bit stream that didn't support split mtu buffers should @@ -444,7 +439,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef #endif bool ignoreServerPacket = false; // assume we'll use this server packet - std::ostringstream debugOutput; // If this packet is from the same server edit as the last packet we accepted from the server // we probably want to use it. @@ -453,8 +447,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // the most recent packet from this server time if (_lastEdited > _lastEditedFromRemote) { ignoreServerPacket = true; - } else { - debugOutput << "adebug fromSameServerEdit for '" << _name.toStdString() << "' le - lefr = " << (_lastEdited - _lastEditedFromRemote) << std::flush; // adebug } } else { // If this isn't from the same sever packet, then honor our skew adjusted times... @@ -462,8 +454,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // then we will not be changing our values, instead we just read and skip the data if (_lastEdited > lastEditedFromBufferAdjusted) { ignoreServerPacket = true; - } else { - debugOutput << "adebug honor skew adjust for '" << _name.toStdString() << "' le - lefba = " << (_lastEdited - lastEditedFromBufferAdjusted) << std::flush; // adebug } } @@ -550,7 +540,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // rules that we expect the server to be using, so it is possible that we'll sometimes ignore // the incoming _simulatorID data (e.g. we might know something that the server does not... yet). - // BOOKMARK TODO adebug: follow pattern where the class unpacks itself + // BOOKMARK TODO adebug: follow pattern where the class unpacks itself? if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { QByteArray simOwnerData; int bytes = OctreePacketData::unpackDataFromBytes(dataAt, simOwnerData); @@ -559,16 +549,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef dataAt += bytes; bytesRead += bytes; - SimulationOwner oldOwner = _simulationOwner; // adebug if (_simulationOwner.set(newSimOwner)) { - std::cout << "adebug something changed: owner = " << _simulationOwner << std::endl; // adebug _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } - if (oldOwner != _simulationOwner) { - std::cout << "adebug ownership changed from " << oldOwner.getID().toString().toStdString() << ":" << int(oldOwner.getPriority()) << " to " - << _simulationOwner.getID().toString().toStdString() << ":" << int(_simulationOwner.getPriority()) - << std::endl; // adebug - } } } @@ -652,11 +635,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // use our simulation helper routine to get a best estimate of where the entity should be. const float MIN_TIME_SKIP = 0.0f; const float MAX_TIME_SKIP = 1.0f; // in seconds - quint64 dt = now - lastSimulatedFromBufferAdjusted; - if (dt > maxSkipTime) { - maxSkipTime = dt; - std::cout << "adebug maxSkipTime = " << maxSkipTime << " for '" << _name.toStdString() << "'" << std::endl; // adebug - } float skipTimeForward = glm::clamp((float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND), MIN_TIME_SKIP, MAX_TIME_SKIP); if (skipTimeForward > 0.0f) { @@ -672,8 +650,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); if (overwriteLocalData) { - // TODO adebug: make this use operator==() - if (_simulationOwner.matchesID(myNodeID)) { + if (_simulationOwner.matchesValidID(myNodeID)) { // we own the simulation, so we keep our transform+velocities and remove any related dirty flags // rather than accept the values in the packet setPosition(savePosition); @@ -682,8 +659,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _angularVelocity = saveAngularVelocity; _dirtyFlags &= ~(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES); } else { - std::cout << "adebug myNode = " << myNodeID.toString().toStdString() << " owner = " << _simulationOwner.getID().toString().toStdString() << std::endl; // adebug - std::cout << debugOutput.str() << std::endl; // adebug _lastSimulated = now; } } @@ -903,11 +878,6 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { } } -void EntityItem::clearDirtyFlags(uint32_t mask) { - // adebug TODO: move this back to header after done debugging - _dirtyFlags &= ~mask; -} - bool EntityItem::isMoving() const { return hasVelocity() || hasAngularVelocity(); } @@ -1041,9 +1011,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); if (somethingChanged) { - if (_name == plankyBlock2) { - std::cout << "adebug update for '" << _name.toStdString() << "'" << std::endl; // adebug - } uint64_t now = usecTimestampNow(); #ifdef WANT_DEBUG int elapsed = now - getLastEdited(); @@ -1411,19 +1378,12 @@ void EntityItem::setSimulationOwner(const SimulationOwner& owner) { } void EntityItem::updateSimulatorID(const QUuid& value) { - QUuid oldID = _simulationOwner.getID(); if (_simulationOwner.setID(value)) { _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; - if (oldID != _simulationOwner.getID() && _name == plankyBlock2) { - std::cout << "adebug updateSimulatorID for '" << _name.toStdString() << "' from " << oldID.toString().toStdString() << " to " << value.toString().toStdString() << std::endl; // adebug - } } } void EntityItem::clearSimulationOwnership() { - if (_name == plankyBlock2) { - std::cout << "adebug clearSimulationOwnership for '" << _name.toStdString() << "'" << std::endl; // adebug - } _simulationOwner.clear(); // don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulatorOwnership() // is only ever called entity-server-side and the flags are only used client-side diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f657a746d8..df369b43f5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -362,8 +362,7 @@ public: virtual void updateShapeType(ShapeType type) { /* do nothing */ } uint32_t getDirtyFlags() const { return _dirtyFlags; } - //void clearDirtyFlags(uint32_t mask = 0xffffffff) { _dirtyFlags &= ~mask; } - void clearDirtyFlags(uint32_t mask = 0xffffffff); + void clearDirtyFlags(uint32_t mask = 0xffffffff) { _dirtyFlags &= ~mask; } bool isMoving() const; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 9979caa9df..698b7fa639 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -17,7 +17,6 @@ #include #include #include -#include // adebug #include "EntitiesLogging.h" #include "EntityItem.h" @@ -712,19 +711,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem LevelDetails propertyLevel = packetData->startLevel(); successPropertyFits = packetData->appendValue(properties._simulationOwner.toByteArray()); if (successPropertyFits) { -// std::cout << "adebug appending ownerhip data" << std::endl; // adebug -// StreamUtil::dump(std::cout, properties._simulationOwner.toByteArray()); propertyFlags |= PROP_SIMULATION_OWNER; propertiesDidntFit -= PROP_SIMULATION_OWNER; propertyCount++; packetData->endLevel(propertyLevel); } else { -// std::cout << "adebug ownership data did not fit" << std::endl; // adebug packetData->discardLevel(propertyLevel); appendState = OctreeElement::PARTIAL; } } else { -// std::cout << "adebug property doesn't have ownerhip data" << std::endl; // adebug propertiesDidntFit -= PROP_SIMULATION_OWNER; } @@ -992,10 +987,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int SimulationOwner simOwner; simOwner.fromByteArray(fromBuffer); properties.setSimulationOwner(simOwner); -// std::cout << "adebug decoding ownerhip data" << std::endl; // adebug -// StreamUtil::dump(std::cout, fromBuffer); - } else { -// std::cout << "adebug no ownership info to decode" << std::endl; // adebug } READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 0693c1e85c..dd3bfd8d67 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include // adebug #include "EntityScriptingInterface.h" #include diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp index f858665260..ecc5dd8b81 100644 --- a/libraries/entities/src/SimulationOwner.cpp +++ b/libraries/entities/src/SimulationOwner.cpp @@ -11,6 +11,7 @@ #include "SimulationOwner.h" +#include // included for tests #include #include @@ -86,7 +87,7 @@ void SimulationOwner::updateExpiry() { _expiry = usecTimestampNow() + OWNERSHIP_LOCKOUT_EXPIRY; } -// TODO: move this test code out +// NOTE: eventually this code will be moved into unit tests // static debug void SimulationOwner::test() { { // test default constructor @@ -153,10 +154,6 @@ void SimulationOwner::test() { } } -bool SimulationOwner::operator==(const SimulationOwner& other) { - return (_id == other._id && _priority == other._priority); -} - bool SimulationOwner::operator!=(const SimulationOwner& other) { return (_id != other._id && _priority != other._priority); } @@ -175,12 +172,6 @@ SimulationOwner& SimulationOwner::operator=(const SimulationOwner& other) { return *this; } -// friend of SimulationOwner -std::ostream& operator<<(std::ostream& s, const SimulationOwner& simOwner) { - s << "{ id : " << simOwner._id.toString().toStdString() << ", priority : " << (int)simOwner._priority << " }"; - return s; -} - QDebug& operator<<(QDebug& d, const SimulationOwner& simOwner) { d << "{ id : " << simOwner << ", priority : " << (int)simOwner._priority << " }"; return d; diff --git a/libraries/entities/src/SimulationOwner.h b/libraries/entities/src/SimulationOwner.h index 449bf85f7a..8f580d10a6 100644 --- a/libraries/entities/src/SimulationOwner.h +++ b/libraries/entities/src/SimulationOwner.h @@ -12,8 +12,6 @@ #ifndef hifi_SimulationOwner_h #define hifi_SimulationOwner_h -#include - #include #include @@ -50,18 +48,18 @@ public: bool set(const SimulationOwner& owner); bool isNull() const { return _id.isNull(); } - bool matchesID(const QUuid& id) const { return _id == id && !_id.isNull(); } + bool matchesValidID(const QUuid& id) const { return _id == id && !_id.isNull(); } void updateExpiry(); bool hasExpired() const { return usecTimestampNow() > _expiry; } bool operator>=(quint8 priority) const { return _priority >= priority; } - bool operator==(const SimulationOwner& other); + bool operator==(const SimulationOwner& other) { return (_id == other._id && _priority == other._priority); } + bool operator!=(const SimulationOwner& other); SimulationOwner& operator=(const SimulationOwner& other); - friend std::ostream& operator<<(std::ostream& s, const SimulationOwner& simOwner); friend QDebug& operator<<(QDebug& d, const SimulationOwner& simOwner); // debug diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 64b0c317bd..b7ac872ae2 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -22,8 +22,6 @@ #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS #include "EntityTree.h" #endif -//const char* plankyBlock = "PlankyBlock46"; // adebug -const char* plankyBlock = "magenta"; // adebug static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; @@ -98,17 +96,10 @@ void EntityMotionState::updateServerPhysicsVariables() { // virtual void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) { assert(entityTreeIsLocked()); -// if (_entity && _entity->getName() == plankyBlock) { -// quint64 dt = (usecTimestampNow() - _activationTime) / 1000; // adebug -// std::cout << "adebug handleEasyChanges flags = 0x" << std::hex << flags << std::dec << " dt = " << dt << std::endl; // adebug -// } updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags, engine); if (flags & EntityItem::DIRTY_SIMULATOR_ID) { -// if (_entity && _entity->getName() == plankyBlock) { -// std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' found DIRTY_SIMULATOR_ID flag" << std::endl; // adebug -// } _loopsWithoutOwner = 0; if (_entity->getSimulatorID().isNull()) { // simulation ownership is being removed @@ -117,26 +108,12 @@ void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) flags &= ~EntityItem::DIRTY_PHYSICS_ACTIVATION; // hint to Bullet that the object is deactivating _body->setActivationState(WANTS_DEACTIVATION); -// if (_entity && _entity->getName() == plankyBlock) { -// std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' clearing ownership so _candidatePriority goes to 0" << std::endl; // adebug -// } - _candidatePriority = 0; - if (_expectedOwnership != -1) { - std::cout << "adebug unexpected loss of ownership '" << _entity->getName().toStdString() << "' expected -1 but got " << _expectedOwnership << std::endl; // adebug - } - _expectedOwnership = 0; + _outgoingPriority = 0; } else { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; - if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulatorPriority() > _candidatePriority) { + if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulatorPriority() > _outgoingPriority) { // we own the simulation or our priority looses to remote -// if (_entity && _entity->getName() == plankyBlock) { -// std::cout << "adebug handleEasyChanges() '" << _entity->getName().toStdString() << "' we own it so _candidatePriority goes to 0" << std::endl; // adebug -// } - if (_expectedOwnership != 1) { - std::cout << "adebug unexpected gain of ownership '" << _entity->getName().toStdString() << "' expected 1 but got " << _expectedOwnership << " _candidatePriority = " << int(_candidatePriority) << std::endl; // adebug - } - _expectedOwnership = 0; - _candidatePriority = 0; + _outgoingPriority = 0; } } } @@ -144,7 +121,7 @@ void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) // also known as "bid for ownership with SCRIPT priority" // we're manipulating this object directly via script, so we artificially // manipulate the logic to trigger an immediate bid for ownership - setSimulatorPriorityHint(SCRIPT_EDIT_SIMULATOR_PRIORITY); + setOutgoingPriority(SCRIPT_EDIT_SIMULATOR_PRIORITY); } if ((flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); @@ -224,11 +201,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_loopsWithoutOwner > LOOPS_FOR_SIMULATION_ORPHAN && usecTimestampNow() > _nextOwnershipBid) { //qDebug() << "Warning -- claiming something I saw moving." << getName(); - quint64 dt = (usecTimestampNow() - _activationTime) / 1000; // adebug - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug setWorldTransform() bid for orphan '" << _entity->getName().toStdString() << "' dt = " << dt << std::endl; // adebug - } - setSimulatorPriorityHint(VOLUNTEER_SIMULATOR_PRIORITY); + setOutgoingPriority(VOLUNTEER_SIMULATOR_PRIORITY); } } @@ -260,7 +233,7 @@ bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const { return false; } assert(entityTreeIsLocked()); - return _candidatePriority > 0 || sessionID == _entity->getSimulatorID(); + return _outgoingPriority > 0 || sessionID == _entity->getSimulatorID(); } bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { @@ -377,13 +350,10 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s if (_entity->getSimulatorID() != sessionID) { // we don't own the simulation, but maybe we should... - if (_candidatePriority > 0) { - if (_candidatePriority < _entity->getSimulatorPriority()) { + if (_outgoingPriority > 0) { + if (_outgoingPriority < _entity->getSimulatorPriority()) { // our priority looses to remote, so we don't bother to bid - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug shouldSendUpdate() '" << _entity->getName().toStdString() << "' clear priority " << int(_candidatePriority) << " in favor of remote priority " << int(_entity->getSimulatorPriority()) << std::endl; // adebug - } - _candidatePriority = 0; + _outgoingPriority = 0; return false; } return usecTimestampNow() > _nextOwnershipBid; @@ -478,28 +448,15 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q if (!active) { // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID // but we remember that we do still own it... and rely on the server to tell us that we don't - std::cout << "adebug releasing ownership of '" << _entity->getName().toStdString() << "' for inactivity" << std::endl; // adebug properties.clearSimulationOwner(); - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug sendUpdate() send clear ownership for '" << _entity->getName().toStdString() << "'" << std::endl; // adebug - } - _expectedOwnership = -1; } else { // re-assert the simulation info properties.setSimulationOwner(sessionID, _entity->getSimulatorPriority()); - _expectedOwnership = 0; } } else { // we don't own the simulation for this entity yet, but we're sending a bid for it - quint64 dt = (usecTimestampNow() - _activationTime) / 1000; // adebug - uint8_t bidPriority = glm::max(_candidatePriority, VOLUNTEER_SIMULATOR_PRIORITY); // adebug - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug sendUpdate() bid for ownership of '" << _entity->getName().toStdString() << "' dt = " << dt << " with priority " << int(bidPriority) << std::endl; // adebug - } - properties.setSimulationOwner(sessionID, glm::max(_candidatePriority, VOLUNTEER_SIMULATOR_PRIORITY)); + properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATOR_PRIORITY)); _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; - _expectedOwnership = 1; - //_candidatePriority = 0; // TODO: it would be nice to not have to clear this until we get a message back that ownership has changed } if (EntityItem::getSendPhysicsUpdates()) { @@ -559,7 +516,7 @@ void EntityMotionState::bump(uint8_t priority) { if (_entity) { //uint8_t inheritedPriority = priority < 2 ? 1 : priority - 1; uint8_t inheritedPriority = VOLUNTEER_SIMULATOR_PRIORITY; - setSimulatorPriorityHint(inheritedPriority); + setOutgoingPriority(inheritedPriority); } } @@ -589,10 +546,6 @@ void EntityMotionState::measureBodyAcceleration() { _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt; _lastVelocity = velocity; if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) { - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug measureBodyAcceleration() activate '" << _entity->getName().toStdString() << "'" << std::endl; // adebug - } - _activationTime = usecTimestampNow(); // adebug _loopsWithoutOwner = 0; _lastStep = ObjectMotionState::getWorldSimulationStep(); _sentInactive = false; @@ -635,12 +588,6 @@ int16_t EntityMotionState::computeCollisionGroup() { return COLLISION_GROUP_DEFAULT; } -void EntityMotionState::setSimulatorPriorityHint(uint8_t priority) { - uint8_t oldPriority = _candidatePriority; - _candidatePriority = glm::max(_candidatePriority, priority); - if (_candidatePriority != oldPriority) { - if (_entity && _entity->getName() == plankyBlock) { - std::cout << "adebug setSimulatorPriorityHint() '" << _entity->getName().toStdString() << "' _candidatePrioity changed from " << int(oldPriority) << " to " << int(_candidatePriority) << std::endl; // adebug - } - } +void EntityMotionState::setOutgoingPriority(uint8_t priority) { + _outgoingPriority = glm::max(_outgoingPriority, priority); } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 34a8c70e30..6d08343286 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -82,7 +82,7 @@ public: virtual int16_t computeCollisionGroup(); // eternal logic can suggest a simuator priority bid for the next outgoing update - void setSimulatorPriorityHint(uint8_t priority); + void setOutgoingPriority(uint8_t priority); friend class PhysicalEntitySimulation; @@ -116,9 +116,7 @@ protected: quint8 _accelerationNearlyGravityCount; quint64 _nextOwnershipBid = 0; uint32_t _loopsWithoutOwner; - uint8_t _candidatePriority = 0; - quint64 _activationTime = 0; // adebug - int _expectedOwnership = 0; // adebug + uint8_t _outgoingPriority = 0; }; #endif // hifi_EntityMotionState_h From 40f6ecd93648561de886fb740a128df73b0b9435 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Jun 2015 11:41:41 -0700 Subject: [PATCH 15/24] fix crash for dereference null pointer --- libraries/entities/src/EntityScriptingInterface.cpp | 8 ++++---- libraries/entities/src/SimulationOwner.cpp | 4 ++-- libraries/entities/src/SimulationOwner.h | 9 +++++---- libraries/physics/src/EntityMotionState.cpp | 8 ++++---- libraries/physics/src/PhysicsEngine.cpp | 10 ++++++---- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index dd3bfd8d67..de9bf09d37 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -78,10 +78,10 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties // This Node is creating a new object. If it's in motion, set this Node as the simulator. auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); - propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); + propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); // and make note of it now, so we can act on it right away. - entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); + entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); entity->setLastBroadcast(usecTimestampNow()); } else { @@ -163,10 +163,10 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper // we re-assert our simulation ownership properties.setSimulationOwner(myNodeID, - glm::max(entity->getSimulatorPriority(), SCRIPT_EDIT_SIMULATOR_PRIORITY)); + glm::max(entity->getSimulatorPriority(), SCRIPT_EDIT_SIMULATION_PRIORITY)); } else { // we make a bid for simulation ownership - properties.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY); + properties.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); entity->flagForOwnership(); } } diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp index ecc5dd8b81..7a275401fb 100644 --- a/libraries/entities/src/SimulationOwner.cpp +++ b/libraries/entities/src/SimulationOwner.cpp @@ -48,8 +48,8 @@ void SimulationOwner::clear() { void SimulationOwner::setPriority(quint8 priority) { _priority = priority; - if (_priority == MAX_SIMULATOR_PRIORITY) { - // we extend the the expiry whenever we set MAX_SIMULATOR_PRIORITY + if (_priority == MAX_SIMULATION_PRIORITY) { + // we extend the the expiry whenever we set MAX_SIMULATION_PRIORITY updateExpiry(); } else if (_priority == 0) { // when priority is zero we clear everything diff --git a/libraries/entities/src/SimulationOwner.h b/libraries/entities/src/SimulationOwner.h index 8f580d10a6..46d621b566 100644 --- a/libraries/entities/src/SimulationOwner.h +++ b/libraries/entities/src/SimulationOwner.h @@ -18,10 +18,11 @@ #include #include -const quint8 VOLUNTEER_SIMULATOR_PRIORITY = 0x01; -const quint8 SCRIPT_EDIT_SIMULATOR_PRIORITY = 0x80; -const quint8 MAX_SIMULATOR_PRIORITY = 0xff; -const quint8 ATTACHMENT_SIMULATOR_PRIORITY = MAX_SIMULATOR_PRIORITY; +const quint8 VOLUNTEER_SIMULATION_PRIORITY = 0x01; +const quint8 PERSONAL_SIMULATION_PRIORITY = 0x7f; +const quint8 SCRIPT_EDIT_SIMULATION_PRIORITY = 0x80; +const quint8 MAX_SIMULATION_PRIORITY = 0xff; +const quint8 ATTACHMENT_SIMULATION_PRIORITY = MAX_SIMULATION_PRIORITY; class SimulationOwner { public: diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index b7ac872ae2..022e6e5d4e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -121,7 +121,7 @@ void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) // also known as "bid for ownership with SCRIPT priority" // we're manipulating this object directly via script, so we artificially // manipulate the logic to trigger an immediate bid for ownership - setOutgoingPriority(SCRIPT_EDIT_SIMULATOR_PRIORITY); + setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY); } if ((flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { _body->activate(); @@ -201,7 +201,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (_loopsWithoutOwner > LOOPS_FOR_SIMULATION_ORPHAN && usecTimestampNow() > _nextOwnershipBid) { //qDebug() << "Warning -- claiming something I saw moving." << getName(); - setOutgoingPriority(VOLUNTEER_SIMULATOR_PRIORITY); + setOutgoingPriority(VOLUNTEER_SIMULATION_PRIORITY); } } @@ -455,7 +455,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q } } else { // we don't own the simulation for this entity yet, but we're sending a bid for it - properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATOR_PRIORITY)); + properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; } @@ -515,7 +515,7 @@ QUuid EntityMotionState::getSimulatorID() const { void EntityMotionState::bump(uint8_t priority) { if (_entity) { //uint8_t inheritedPriority = priority < 2 ? 1 : priority - 1; - uint8_t inheritedPriority = VOLUNTEER_SIMULATOR_PRIORITY; + uint8_t inheritedPriority = VOLUNTEER_SIMULATION_PRIORITY; setOutgoingPriority(inheritedPriority); } } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index a200abede2..2c7c39f222 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -270,13 +270,15 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const // NOTE: we might own the simulation of a kinematic object (A) // but we don't claim ownership of kinematic objects (B) based on collisions here. if (!objectB->isStaticOrKinematicObject() && b->getSimulatorID() != _sessionID) { - b->bump(a->getSimulatorPriority()); + quint8 priority = a ? a->getSimulatorPriority() : PERSONAL_SIMULATION_PRIORITY; + b->bump(priority); } } else if (a && ((b && b->getSimulatorID() == _sessionID && !objectB->isStaticObject()) || (objectB == characterObject))) { // SIMILARLY: we might own the simulation of a kinematic object (B) // but we don't claim ownership of kinematic objects (A) based on collisions here. if (!objectA->isStaticOrKinematicObject() && a->getSimulatorID() != _sessionID) { - a->bump(b->getSimulatorPriority()); + quint8 priority = b ? b->getSimulatorPriority() : PERSONAL_SIMULATION_PRIORITY; + a->bump(priority); } } } @@ -401,7 +403,7 @@ void PhysicsEngine::bump(ObjectMotionState* motionState) { if (!objectA->isStaticOrKinematicObject()) { ObjectMotionState* motionStateA = static_cast(objectA->getUserPointer()); if (motionStateA) { - motionStateA->bump(VOLUNTEER_SIMULATOR_PRIORITY); + motionStateA->bump(VOLUNTEER_SIMULATION_PRIORITY); objectA->setActivationState(ACTIVE_TAG); } } @@ -409,7 +411,7 @@ void PhysicsEngine::bump(ObjectMotionState* motionState) { if (!objectB->isStaticOrKinematicObject()) { ObjectMotionState* motionStateB = static_cast(objectB->getUserPointer()); if (motionStateB) { - motionStateB->bump(VOLUNTEER_SIMULATOR_PRIORITY); + motionStateB->bump(VOLUNTEER_SIMULATION_PRIORITY); objectB->setActivationState(ACTIVE_TAG); } } From 1ba937eab903f6c71992b41d1be12c17e623eaf6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 26 Jun 2015 08:46:55 -0700 Subject: [PATCH 16/24] fix bug in streaming of SimulationOwner class --- libraries/entities/src/SimulationOwner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp index 7a275401fb..88bb3fcab3 100644 --- a/libraries/entities/src/SimulationOwner.cpp +++ b/libraries/entities/src/SimulationOwner.cpp @@ -173,7 +173,7 @@ SimulationOwner& SimulationOwner::operator=(const SimulationOwner& other) { } QDebug& operator<<(QDebug& d, const SimulationOwner& simOwner) { - d << "{ id : " << simOwner << ", priority : " << (int)simOwner._priority << " }"; + d << "{ id : " << simOwner._id << ", priority : " << (int)simOwner._priority << " }"; return d; } From ff67b54f8710e0e296eaa86f421b256b26b0c9fe Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 26 Jun 2015 08:47:21 -0700 Subject: [PATCH 17/24] don't read terse update data for objs we own --- libraries/entities/src/EntityItem.cpp | 33 +++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 60d7c5a4d1..ff262d3e87 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -534,13 +534,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef dataAt += propertyFlags.getEncodedLength(); bytesRead += propertyFlags.getEncodedLength(); + bool weOwnIt = false; if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER) { // NOTE: the server is authoritative for changes to simOwnerID so we always unpack this data, // even when we would otherwise ignore the rest of the packet. That said, we assert the priority // rules that we expect the server to be using, so it is possible that we'll sometimes ignore // the incoming _simulatorID data (e.g. we might know something that the server does not... yet). - // BOOKMARK TODO adebug: follow pattern where the class unpacks itself? if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { QByteArray simOwnerData; int bytes = OctreePacketData::unpackDataFromBytes(dataAt, simOwnerData); @@ -553,28 +553,27 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } } + auto nodeList = DependencyManager::get(); + weOwnIt = _simulationOwner.matchesValidID(nodeList->getSessionUUID()); } + bool oldOverwrite = overwriteLocalData; + overwriteLocalData = overwriteLocalData && !weOwnIt; READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); + overwriteLocalData = oldOverwrite; - // Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS - if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) { - if (propertyFlags.getHasProperty(PROP_RADIUS)) { - float fromBuffer; - memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); - dataAt += sizeof(fromBuffer); - bytesRead += sizeof(fromBuffer); - if (overwriteLocalData) { - setRadius(fromBuffer); - } - } - } else { - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); - } + READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); + overwriteLocalData = overwriteLocalData && !weOwnIt; READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); + overwriteLocalData = oldOverwrite; + READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity); + + overwriteLocalData = overwriteLocalData && !weOwnIt; READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity); + overwriteLocalData = oldOverwrite; + READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity); if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration); @@ -587,7 +586,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript); READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); + + overwriteLocalData = overwriteLocalData && !weOwnIt; READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); + overwriteLocalData = oldOverwrite; + READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); From d6c69e8fe6ef8bb689337db9563f8fdb3e3d8962 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 26 Jun 2015 12:05:27 -0700 Subject: [PATCH 18/24] pack terse update parameters near each other also don't constantly resend ownership data --- libraries/entities/src/EntityItem.cpp | 114 ++++++++++-------- .../entities/src/EntityItemProperties.cpp | 6 +- libraries/physics/src/EntityMotionState.cpp | 6 +- 3 files changed, 69 insertions(+), 57 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ff262d3e87..1cfa992526 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -102,12 +102,14 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_SIMULATION_OWNER; requestedProperties += PROP_POSITION; - requestedProperties += PROP_DIMENSIONS; // NOTE: PROP_RADIUS obsolete requestedProperties += PROP_ROTATION; - requestedProperties += PROP_DENSITY; requestedProperties += PROP_VELOCITY; - requestedProperties += PROP_GRAVITY; + requestedProperties += PROP_ANGULAR_VELOCITY; requestedProperties += PROP_ACCELERATION; + + requestedProperties += PROP_DIMENSIONS; // NOTE: PROP_RADIUS obsolete + requestedProperties += PROP_DENSITY; + requestedProperties += PROP_GRAVITY; requestedProperties += PROP_DAMPING; requestedProperties += PROP_RESTITUTION; requestedProperties += PROP_FRICTION; @@ -116,7 +118,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_SCRIPT_TIMESTAMP; requestedProperties += PROP_COLLISION_SOUND_URL; requestedProperties += PROP_REGISTRATION_POINT; - requestedProperties += PROP_ANGULAR_VELOCITY; requestedProperties += PROP_ANGULAR_DAMPING; requestedProperties += PROP_VISIBLE; requestedProperties += PROP_IGNORE_FOR_COLLISIONS; @@ -234,12 +235,14 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); APPEND_ENTITY_PROPERTY(PROP_POSITION, getPosition()); - APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions()); // NOTE: PROP_RADIUS obsolete APPEND_ENTITY_PROPERTY(PROP_ROTATION, getRotation()); - APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, getVelocity()); - APPEND_ENTITY_PROPERTY(PROP_GRAVITY, getGravity()); + APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration()); + + APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions()); // NOTE: PROP_RADIUS obsolete + APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity()); + APPEND_ENTITY_PROPERTY(PROP_GRAVITY, getGravity()); APPEND_ENTITY_PROPERTY(PROP_DAMPING, getDamping()); APPEND_ENTITY_PROPERTY(PROP_RESTITUTION, getRestitution()); APPEND_ENTITY_PROPERTY(PROP_FRICTION, getFriction()); @@ -247,7 +250,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_SCRIPT, getScript()); APPEND_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, getScriptTimestamp()); APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint()); - APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, getIgnoreForCollisions()); @@ -534,12 +536,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef dataAt += propertyFlags.getEncodedLength(); bytesRead += propertyFlags.getEncodedLength(); - bool weOwnIt = false; if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER) { - // NOTE: the server is authoritative for changes to simOwnerID so we always unpack this data, - // even when we would otherwise ignore the rest of the packet. That said, we assert the priority - // rules that we expect the server to be using, so it is possible that we'll sometimes ignore - // the incoming _simulatorID data (e.g. we might know something that the server does not... yet). + // pack SimulationOwner and terse update properties near each other + + // NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data + // even when we would otherwise ignore the rest of the packet. if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { QByteArray simOwnerData; @@ -549,48 +550,58 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef dataAt += bytes; bytesRead += bytes; - if (_simulationOwner.set(newSimOwner)) { - _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; + if (overwriteLocalData) { + if (_simulationOwner.set(newSimOwner)) { + _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; + } } } - auto nodeList = DependencyManager::get(); - weOwnIt = _simulationOwner.matchesValidID(nodeList->getSessionUUID()); - } + { + auto nodeList = DependencyManager::get(); + bool weOwnIt = _simulationOwner.matchesValidID(nodeList->getSessionUUID()); + // When we own the simulation we don't accept updates to the entity's transform/velocities + // but since we're using macros below we have to temporarily modify overwriteLocalData. + bool oldOverwrite = overwriteLocalData; + overwriteLocalData = overwriteLocalData && !weOwnIt; + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); + READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); + READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity); + READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); + READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration); + overwriteLocalData = oldOverwrite; + } - bool oldOverwrite = overwriteLocalData; - overwriteLocalData = overwriteLocalData && !weOwnIt; - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); - overwriteLocalData = oldOverwrite; - - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); - - overwriteLocalData = overwriteLocalData && !weOwnIt; - READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); - overwriteLocalData = oldOverwrite; - - READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity); - - overwriteLocalData = overwriteLocalData && !weOwnIt; - READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity); - overwriteLocalData = oldOverwrite; - - READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity); - if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { + READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); + READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity); + READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity); + + READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping); + READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution); + READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction); + READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime); + READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript); + READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); + READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); + } else { + // legacy order of packing here + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); + READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); + READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); + READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity); + READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity); + READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity); READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration); + + READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping); + READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution); + READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction); + READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime); + READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript); + READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); + READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); + READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); } - READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping); - READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution); - READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction); - READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime); - READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript); - READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); - READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); - - overwriteLocalData = overwriteLocalData && !weOwnIt; - READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); - overwriteLocalData = oldOverwrite; - READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); @@ -598,8 +609,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); - if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION && - args.bitstreamVersion < VERSION_ENTITIES_HAVE_SIMULATION_OWNER) { + if (args.bitstreamVersion < VERSION_ENTITIES_HAVE_SIMULATION_OWNER) { + // this code for when there is only simulatorID and no simulation priority + // we always accept the server's notion of simulatorID, so we fake overwriteLocalData as true // before we try to READ_ENTITY_PROPERTY it bool temp = overwriteLocalData; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 698b7fa639..1de875be92 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1268,6 +1268,8 @@ void EntityItemProperties::clearSimulationOwner() { } void EntityItemProperties::setSimulationOwner(const QUuid& id, uint8_t priority) { - _simulationOwner.set(id, priority); - _simulationOwnerChanged = true; + if (!_simulationOwner.matchesValidID(id) || _simulationOwner.getPriority() != priority) { + _simulationOwner.set(id, priority); + _simulationOwnerChanged = true; + } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 022e6e5d4e..f7f6c629a9 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -422,7 +422,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q _serverAcceleration = _entity->getAcceleration(); _serverAngularVelocity = _entity->getAngularVelocity(); - EntityItemProperties properties = _entity->getProperties(); + EntityItemProperties properties; // explicitly set the properties that changed so that they will be packed properties.setPosition(_serverPosition); @@ -449,10 +449,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID // but we remember that we do still own it... and rely on the server to tell us that we don't properties.clearSimulationOwner(); - } else { - // re-assert the simulation info - properties.setSimulationOwner(sessionID, _entity->getSimulatorPriority()); } + // else the ownership is not changing so we don't bother to pack it } else { // we don't own the simulation for this entity yet, but we're sending a bid for it properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); From e18506c77f11a3f8e8d4a0f49d14d5d74b769db9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 26 Jun 2015 15:30:18 -0700 Subject: [PATCH 19/24] promote volunteer priority also remove some cruft change uint8_t to be quint8 --- libraries/entities/src/EntityItem.cpp | 4 ++++ libraries/entities/src/EntityItem.h | 3 ++- .../entities/src/EntityScriptingInterface.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 6 +++++- libraries/entities/src/SimulationOwner.cpp | 12 ++++++++---- libraries/entities/src/SimulationOwner.h | 15 ++++++++++++--- libraries/physics/src/EntityMotionState.cpp | 19 +++++++++---------- libraries/physics/src/EntityMotionState.h | 8 ++++---- libraries/physics/src/ObjectMotionState.h | 4 ++-- libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 10 files changed, 49 insertions(+), 28 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1cfa992526..09cdb0a776 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1392,6 +1392,10 @@ void EntityItem::setSimulationOwner(const SimulationOwner& owner) { _simulationOwner.set(owner); } +void EntityItem::promoteSimulationPriority(quint8 priority) { + _simulationOwner.promotePriority(priority); +} + void EntityItem::updateSimulatorID(const QUuid& value) { if (_simulationOwner.setID(value)) { _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index df369b43f5..d8371e545d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -321,8 +321,9 @@ public: const SimulationOwner& getSimulationOwner() const { return _simulationOwner; } void setSimulationOwner(const QUuid& id, quint8 priority); void setSimulationOwner(const SimulationOwner& owner); + void promoteSimulationPriority(quint8 priority); - quint8 getSimulatorPriority() const { return _simulationOwner.getPriority(); } + quint8 getSimulationPriority() const { return _simulationOwner.getPriority(); } QUuid getSimulatorID() const { return _simulationOwner.getID(); } void updateSimulatorID(const QUuid& value); void clearSimulationOwnership(); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index de9bf09d37..8fdbe479e6 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -163,7 +163,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper // we re-assert our simulation ownership properties.setSimulationOwner(myNodeID, - glm::max(entity->getSimulatorPriority(), SCRIPT_EDIT_SIMULATION_PRIORITY)); + glm::max(entity->getSimulationPriority(), SCRIPT_EDIT_SIMULATION_PRIORITY)); } else { // we make a bid for simulation ownership properties.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 45b5a95271..3f38e18a9e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -169,7 +169,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI // so we apply the rules for ownership change: // (1) higher priority wins // (2) equal priority wins if ownership filter has expired except... - uint8_t oldPriority = entity->getSimulatorPriority(); + uint8_t oldPriority = entity->getSimulationPriority(); uint8_t newPriority = properties.getSimulationOwner().getPriority(); if (newPriority > oldPriority || (newPriority == oldPriority && properties.getSimulationOwner().hasExpired())) { @@ -208,6 +208,10 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI _simulation->lock(); _simulation->changeEntity(entity); _simulation->unlock(); + // always promote volunteer priority + if (entity->getSimulationPriority() == VOLUNTEER_SIMULATION_PRIORITY) { + entity->promoteSimulationPriority(RECRUIT_SIMULATION_PRIORITY); + } } } else { // normally the _simulation clears ALL updateFlags, but since there is none we do it explicitly diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp index 88bb3fcab3..eb5f8b6ecd 100644 --- a/libraries/entities/src/SimulationOwner.cpp +++ b/libraries/entities/src/SimulationOwner.cpp @@ -48,16 +48,20 @@ void SimulationOwner::clear() { void SimulationOwner::setPriority(quint8 priority) { _priority = priority; - if (_priority == MAX_SIMULATION_PRIORITY) { - // we extend the the expiry whenever we set MAX_SIMULATION_PRIORITY - updateExpiry(); - } else if (_priority == 0) { + if (_priority == 0) { // when priority is zero we clear everything _expiry = 0; _id = QUuid(); } } +void SimulationOwner::promotePriority(quint8 priority) { + if (priority > _priority) { + _priority = priority; + updateExpiry(); + } +} + bool SimulationOwner::setID(const QUuid& id) { if (_id != id) { _id = id; diff --git a/libraries/entities/src/SimulationOwner.h b/libraries/entities/src/SimulationOwner.h index 46d621b566..325be54e62 100644 --- a/libraries/entities/src/SimulationOwner.h +++ b/libraries/entities/src/SimulationOwner.h @@ -18,11 +18,19 @@ #include #include +// Simulation observers will bid to simulate unowned active objects at the lowest possible priority +// which is VOLUNTEER. If the server accepts a VOLUNTEER bid it will automatically bump it +// to RECRUIT priority so that other volunteers don't accidentally take over. const quint8 VOLUNTEER_SIMULATION_PRIORITY = 0x01; -const quint8 PERSONAL_SIMULATION_PRIORITY = 0x7f; +const quint8 RECRUIT_SIMULATION_PRIORITY = VOLUNTEER_SIMULATION_PRIORITY + 1; + +// When poking objects with scripts an observer will bid at SCRIPT_EDIT priority. const quint8 SCRIPT_EDIT_SIMULATION_PRIORITY = 0x80; -const quint8 MAX_SIMULATION_PRIORITY = 0xff; -const quint8 ATTACHMENT_SIMULATION_PRIORITY = MAX_SIMULATION_PRIORITY; + +// PERSONAL priority (needs a better name) is the level at which a simulation observer will bid for +// objects that collide its MyAvatar. +const quint8 PERSONAL_SIMULATION_PRIORITY = SCRIPT_EDIT_SIMULATION_PRIORITY - 1; + class SimulationOwner { public: @@ -42,6 +50,7 @@ public: void clear(); void setPriority(quint8 priority); + void promotePriority(quint8 priority); // return true if id is changed bool setID(const QUuid& id); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f7f6c629a9..884eccb609 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -111,7 +111,7 @@ void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) _outgoingPriority = 0; } else { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; - if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulatorPriority() > _outgoingPriority) { + if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() > _outgoingPriority) { // we own the simulation or our priority looses to remote _outgoingPriority = 0; } @@ -351,7 +351,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s if (_entity->getSimulatorID() != sessionID) { // we don't own the simulation, but maybe we should... if (_outgoingPriority > 0) { - if (_outgoingPriority < _entity->getSimulatorPriority()) { + if (_outgoingPriority < _entity->getSimulationPriority()) { // our priority looses to remote, so we don't bother to bid _outgoingPriority = 0; return false; @@ -453,7 +453,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q // else the ownership is not changing so we don't bother to pack it } else { // we don't own the simulation for this entity yet, but we're sending a bid for it - properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); + properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; } @@ -493,9 +493,9 @@ uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() { } // virtual -uint8_t EntityMotionState::getSimulatorPriority() const { +quint8 EntityMotionState::getSimulationPriority() const { if (_entity) { - return _entity->getSimulatorPriority(); + return _entity->getSimulationPriority(); } return 0; } @@ -510,10 +510,9 @@ QUuid EntityMotionState::getSimulatorID() const { } // virtual -void EntityMotionState::bump(uint8_t priority) { +void EntityMotionState::bump(quint8 priority) { if (_entity) { - //uint8_t inheritedPriority = priority < 2 ? 1 : priority - 1; - uint8_t inheritedPriority = VOLUNTEER_SIMULATION_PRIORITY; + quint8 inheritedPriority = VOLUNTEER_SIMULATION_PRIORITY; setOutgoingPriority(inheritedPriority); } } @@ -586,6 +585,6 @@ int16_t EntityMotionState::computeCollisionGroup() { return COLLISION_GROUP_DEFAULT; } -void EntityMotionState::setOutgoingPriority(uint8_t priority) { - _outgoingPriority = glm::max(_outgoingPriority, priority); +void EntityMotionState::setOutgoingPriority(quint8 priority) { + _outgoingPriority = glm::max(_outgoingPriority, priority); } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 6d08343286..9f7bafd416 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -68,9 +68,9 @@ public: virtual const QUuid& getObjectID() const { return _entity->getID(); } - virtual uint8_t getSimulatorPriority() const; + virtual quint8 getSimulationPriority() const; virtual QUuid getSimulatorID() const; - virtual void bump(uint8_t priority); + virtual void bump(quint8 priority); EntityItemPointer getEntity() const { return _entity; } @@ -82,7 +82,7 @@ public: virtual int16_t computeCollisionGroup(); // eternal logic can suggest a simuator priority bid for the next outgoing update - void setOutgoingPriority(uint8_t priority); + void setOutgoingPriority(quint8 priority); friend class PhysicalEntitySimulation; @@ -116,7 +116,7 @@ protected: quint8 _accelerationNearlyGravityCount; quint64 _nextOwnershipBid = 0; uint32_t _loopsWithoutOwner; - uint8_t _outgoingPriority = 0; + quint8 _outgoingPriority = 0; }; #endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 1ef3ac0dcd..30394ef5fc 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -119,9 +119,9 @@ public: virtual const QUuid& getObjectID() const = 0; - virtual uint8_t getSimulatorPriority() const { return 0; } + virtual quint8 getSimulationPriority() const { return 0; } virtual QUuid getSimulatorID() const = 0; - virtual void bump(uint8_t priority) {} + virtual void bump(quint8 priority) {} virtual QString getName() { return ""; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 2c7c39f222..5c586eb09d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -270,14 +270,14 @@ void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const // NOTE: we might own the simulation of a kinematic object (A) // but we don't claim ownership of kinematic objects (B) based on collisions here. if (!objectB->isStaticOrKinematicObject() && b->getSimulatorID() != _sessionID) { - quint8 priority = a ? a->getSimulatorPriority() : PERSONAL_SIMULATION_PRIORITY; + quint8 priority = a ? a->getSimulationPriority() : PERSONAL_SIMULATION_PRIORITY; b->bump(priority); } } else if (a && ((b && b->getSimulatorID() == _sessionID && !objectB->isStaticObject()) || (objectB == characterObject))) { // SIMILARLY: we might own the simulation of a kinematic object (B) // but we don't claim ownership of kinematic objects (A) based on collisions here. if (!objectA->isStaticOrKinematicObject() && a->getSimulatorID() != _sessionID) { - quint8 priority = b ? b->getSimulatorPriority() : PERSONAL_SIMULATION_PRIORITY; + quint8 priority = b ? b->getSimulationPriority() : PERSONAL_SIMULATION_PRIORITY; a->bump(priority); } } From f274958beb8c29d5cf7df9c5be2ed4ce1d25b99e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 26 Jun 2015 22:13:06 -0700 Subject: [PATCH 20/24] fix bad merge during rebase --- libraries/networking/src/PacketHeaders.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 52a45ea913..488c1f2a79 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -186,6 +186,6 @@ const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29; const PacketVersion VERSION_ENTITIES_FACE_CAMERA = 30; const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 31; const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32; -const PacketVersion VERSION_ENTITIES_HAVE_SIMULATOR_PRIORITY = 33; +const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER = 33; #endif // hifi_PacketHeaders_h From 4d4b97fe5947631b904df7aca8ec1a056d1fdfd6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 26 Jun 2015 22:30:06 -0700 Subject: [PATCH 21/24] add priority promotion to reduce volunteer races also fix priority inheritance from chained collisions --- libraries/entities/src/EntityItem.cpp | 36 +++++-------------- .../entities/src/EntityItemProperties.cpp | 2 -- libraries/entities/src/EntityItemProperties.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 2 +- .../entities/src/EntityScriptingInterface.cpp | 8 +++-- libraries/entities/src/EntityTree.cpp | 13 ++++--- libraries/entities/src/SimulationOwner.cpp | 2 -- libraries/octree/src/OctreePacketData.h | 2 -- libraries/physics/src/EntityMotionState.cpp | 6 ++-- 9 files changed, 26 insertions(+), 46 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 09cdb0a776..587b822013 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -349,12 +349,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef return 0; } - // if this bitstream indicates that this node is the simulation owner, ignore any physics-related updates. - glm::vec3 savePosition = getPosition(); - glm::quat saveRotation = getRotation(); - glm::vec3 saveVelocity = _velocity; - glm::vec3 saveAngularVelocity = _angularVelocity; - int originalLength = bytesLeftToRead; // TODO: figure out a way to avoid the big deep copy below. QByteArray originalDataBuffer((const char*)data, originalLength); // big deep copy! @@ -550,17 +544,14 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef dataAt += bytes; bytesRead += bytes; - if (overwriteLocalData) { - if (_simulationOwner.set(newSimOwner)) { - _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; - } + if (_simulationOwner.set(newSimOwner)) { + _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } } - { + { // When we own the simulation we don't accept updates to the entity's transform/velocities + // but since we're using macros below we have to temporarily modify overwriteLocalData. auto nodeList = DependencyManager::get(); bool weOwnIt = _simulationOwner.matchesValidID(nodeList->getSessionUUID()); - // When we own the simulation we don't accept updates to the entity's transform/velocities - // but since we're using macros below we have to temporarily modify overwriteLocalData. bool oldOverwrite = overwriteLocalData; overwriteLocalData = overwriteLocalData && !weOwnIt; READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); @@ -665,15 +656,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); if (overwriteLocalData) { - if (_simulationOwner.matchesValidID(myNodeID)) { - // we own the simulation, so we keep our transform+velocities and remove any related dirty flags - // rather than accept the values in the packet - setPosition(savePosition); - setRotation(saveRotation); - _velocity = saveVelocity; - _angularVelocity = saveAngularVelocity; - _dirtyFlags &= ~(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES); - } else { + if (!_simulationOwner.matchesValidID(myNodeID)) { + _lastSimulated = now; } } @@ -988,6 +972,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; // these affect TerseUpdate properties + SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation); SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocity); @@ -1009,7 +994,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); // non-simulation properties below SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); @@ -1392,10 +1376,6 @@ void EntityItem::setSimulationOwner(const SimulationOwner& owner) { _simulationOwner.set(owner); } -void EntityItem::promoteSimulationPriority(quint8 priority) { - _simulationOwner.promotePriority(priority); -} - void EntityItem::updateSimulatorID(const QUuid& value) { if (_simulationOwner.setID(value)) { _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; @@ -1404,7 +1384,7 @@ void EntityItem::updateSimulatorID(const QUuid& value) { void EntityItem::clearSimulationOwnership() { _simulationOwner.clear(); - // don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulatorOwnership() + // don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulationOwnership() // is only ever called entity-server-side and the flags are only used client-side //_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1de875be92..ae37d61e5f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -706,7 +706,6 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, - // adebug TODO: convert this to use APPEND_ENTITY_PROPERTY(P,V) macro? if (requestedProperties.getHasProperty(PROP_SIMULATION_OWNER)) { LevelDetails propertyLevel = packetData->startLevel(); successPropertyFits = packetData->appendValue(properties._simulationOwner.toByteArray()); @@ -977,7 +976,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int dataAt += propertyFlags.getEncodedLength(); processedBytes += propertyFlags.getEncodedLength(); - // adebug TODO: convert this to use READ_ENTITY_PROPERTY_TO_PROPERTIES macro? if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { QByteArray fromBuffer; int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index f84e897331..32190664e4 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -210,6 +210,7 @@ public: void clearSimulationOwner(); void setSimulationOwner(const QUuid& id, uint8_t priority); + void promoteSimulationPriority(quint8 priority) { _simulationOwner.promotePriority(priority); } private: QUuid _id; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 163870c225..be4e818a4d 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -121,10 +121,10 @@ enum EntityPropertyList { // used by hyperlinks PROP_HREF, PROP_DESCRIPTION, - PROP_SIMULATION_OWNER, PROP_FACE_CAMERA, PROP_SCRIPT_TIMESTAMP, + PROP_SIMULATION_OWNER, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties ABOVE this line diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8fdbe479e6..c3ba03315a 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -161,9 +161,11 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper // proxy toward the true physical position" feature to hide the final glitches in the remote watcher's // simulation. - // we re-assert our simulation ownership - properties.setSimulationOwner(myNodeID, - glm::max(entity->getSimulationPriority(), SCRIPT_EDIT_SIMULATION_PRIORITY)); + if (entity->getSimulationPriority() < SCRIPT_EDIT_SIMULATION_PRIORITY) { + // we re-assert our simulation ownership at a higher priority + properties.setSimulationOwner(myNodeID, + glm::max(entity->getSimulationPriority(), SCRIPT_EDIT_SIMULATION_PRIORITY)); + } } else { // we make a bid for simulation ownership properties.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 3f38e18a9e..3d5878784a 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -162,7 +162,12 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI // else: We assume the sender really did believe it was the simulation owner when it sent } else if (submittedID == senderID) { // the sender is trying to take or continue ownership - if (entity->getSimulatorID().isNull() || entity->getSimulatorID() == senderID) { + if (entity->getSimulatorID().isNull()) { + // the sender it taking ownership + properties.promoteSimulationPriority(RECRUIT_SIMULATION_PRIORITY); + simulationBlocked = false; + } else if (entity->getSimulatorID() == senderID) { + // the sender is asserting ownership simulationBlocked = false; } else { // the sender is trying to steal ownership from another simulator @@ -180,6 +185,8 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI // the entire update is suspect --> ignore it return false; } + } else { + simulationBlocked = senderID != entity->getSimulatorID(); } if (simulationBlocked) { // squash ownership and physics-related changes. @@ -208,10 +215,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI _simulation->lock(); _simulation->changeEntity(entity); _simulation->unlock(); - // always promote volunteer priority - if (entity->getSimulationPriority() == VOLUNTEER_SIMULATION_PRIORITY) { - entity->promoteSimulationPriority(RECRUIT_SIMULATION_PRIORITY); - } } } else { // normally the _simulation clears ALL updateFlags, but since there is none we do it explicitly diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp index eb5f8b6ecd..d6957873e2 100644 --- a/libraries/entities/src/SimulationOwner.cpp +++ b/libraries/entities/src/SimulationOwner.cpp @@ -67,9 +67,7 @@ bool SimulationOwner::setID(const QUuid& id) { _id = id; updateExpiry(); if (_id.isNull()) { - // when id is null we clear everything _priority = 0; - _expiry = 0; } return true; } diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 20d3db72c8..0ef5039fb0 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -249,8 +249,6 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result); - QByteArray getRawData() const { return QByteArray((const char*)_uncompressed, _bytesInUse); } // adebug - private: /// appends raw bytes, might fail if byte would cause packet to be too large bool append(const unsigned char* data, int length); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 884eccb609..b690e4f40a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -118,7 +118,7 @@ void EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) } } if (flags & EntityItem::DIRTY_SIMULATOR_OWNERSHIP) { - // also known as "bid for ownership with SCRIPT priority" + // (DIRTY_SIMULATOR_OWNERSHIP really means "we should bid for ownership with SCRIPT priority") // we're manipulating this object directly via script, so we artificially // manipulate the logic to trigger an immediate bid for ownership setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY); @@ -449,6 +449,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID // but we remember that we do still own it... and rely on the server to tell us that we don't properties.clearSimulationOwner(); + _outgoingPriority = 0; } // else the ownership is not changing so we don't bother to pack it } else { @@ -512,8 +513,7 @@ QUuid EntityMotionState::getSimulatorID() const { // virtual void EntityMotionState::bump(quint8 priority) { if (_entity) { - quint8 inheritedPriority = VOLUNTEER_SIMULATION_PRIORITY; - setOutgoingPriority(inheritedPriority); + setOutgoingPriority(glm::max(VOLUNTEER_SIMULATION_PRIORITY, --priority)); } } From 426b343e2c582bf96719a8460a82d5f74a31b49b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 26 Jun 2015 23:12:48 -0700 Subject: [PATCH 22/24] remove cruft canAppendBytes() method --- libraries/octree/src/OctreePacketData.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 0ef5039fb0..e6f86bb861 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -188,8 +188,6 @@ public: bool appendRawData(const unsigned char* data, int length); bool appendRawData(QByteArray data); - bool canAppendBytes(int numBytes) const { return _bytesAvailable > numBytes; } - /// returns a byte offset from beginning of the uncompressed stream based on offset from end. /// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; } From 769755e30a0f91828fe0d2cfe7b9dbef759a42b4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Jun 2015 06:20:14 -0700 Subject: [PATCH 23/24] recycle PROP_SIMULATOR_ID --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityPropertyFlags.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 587b822013..a546f252f6 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -607,7 +607,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // before we try to READ_ENTITY_PROPERTY it bool temp = overwriteLocalData; overwriteLocalData = true; - READ_ENTITY_PROPERTY(PROP_SIMULATOR_ID, QUuid, updateSimulatorID); + READ_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, QUuid, updateSimulatorID); overwriteLocalData = temp; } diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index be4e818a4d..244c541362 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -104,7 +104,7 @@ enum EntityPropertyList { PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities PROP_MARKETPLACE_ID, // all entities PROP_ACCELERATION, // all entities - PROP_SIMULATOR_ID, // unused + PROP_SIMULATION_OWNER, // formerly known as PROP_SIMULATOR_ID PROP_NAME, // all entities PROP_COLLISION_SOUND_URL, PROP_RESTITUTION, @@ -124,7 +124,6 @@ enum EntityPropertyList { PROP_FACE_CAMERA, PROP_SCRIPT_TIMESTAMP, - PROP_SIMULATION_OWNER, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties ABOVE this line From 513285a00e6216c891fdcff3edb31803a620248b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 29 Jun 2015 07:27:34 -0700 Subject: [PATCH 24/24] use macros for packing/unpacking QByteArray --- .../entities/src/EntityItemProperties.cpp | 35 +++++-------------- libraries/entities/src/EntityItemProperties.h | 1 + 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index ae37d61e5f..2705933b72 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -706,22 +706,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, - if (requestedProperties.getHasProperty(PROP_SIMULATION_OWNER)) { - LevelDetails propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(properties._simulationOwner.toByteArray()); - if (successPropertyFits) { - propertyFlags |= PROP_SIMULATION_OWNER; - propertiesDidntFit -= PROP_SIMULATION_OWNER; - propertyCount++; - packetData->endLevel(propertyLevel); - } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; - } - } else { - propertiesDidntFit -= PROP_SIMULATION_OWNER; - } - + APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, properties._simulationOwner.toByteArray()); APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition()); APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete APPEND_ENTITY_PROPERTY(PROP_ROTATION, properties.getRotation()); @@ -976,17 +961,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int dataAt += propertyFlags.getEncodedLength(); processedBytes += propertyFlags.getEncodedLength(); - if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { - QByteArray fromBuffer; - int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); - - dataAt += bytes; - processedBytes += bytes; - SimulationOwner simOwner; - simOwner.fromByteArray(fromBuffer); - properties.setSimulationOwner(simOwner); - } - + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATION_OWNER, QByteArray, setSimulationOwner); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATION, glm::quat, setRotation); @@ -1271,3 +1246,9 @@ void EntityItemProperties::setSimulationOwner(const QUuid& id, uint8_t priority) _simulationOwnerChanged = true; } } + +void EntityItemProperties::setSimulationOwner(const QByteArray& data) { + if (_simulationOwner.fromByteArray(data)) { + _simulationOwnerChanged = true; + } +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 32190664e4..3ad12a03f5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -210,6 +210,7 @@ public: void clearSimulationOwner(); void setSimulationOwner(const QUuid& id, uint8_t priority); + void setSimulationOwner(const QByteArray& data); void promoteSimulationPriority(quint8 priority) { _simulationOwner.promotePriority(priority); } private: