XOR incoming trait instance IDs for other avatars

This commit is contained in:
Stephen Birarda 2018-08-31 16:31:33 -07:00
parent 20912349a4
commit 9b3d9dd0f3
5 changed files with 47 additions and 24 deletions

View file

@ -1193,6 +1193,9 @@ public:
void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; }
int getReplicaIndex() { return _replicaIndex; }
const AvatarTraits::TraitInstanceID getTraitInstanceXORID() const { return _traitInstanceXORID; }
void cycleTraitInstanceXORID() { _traitInstanceXORID = QUuid::createUuid(); }
signals:
/**jsdoc
@ -1499,6 +1502,8 @@ private:
// privatize the copy constructor and assignment operator so they cannot be called
AvatarData(const AvatarData&);
AvatarData& operator= (const AvatarData&);
AvatarTraits::TraitInstanceID _traitInstanceXORID { QUuid::createUuid() };
};
Q_DECLARE_METATYPE(AvatarData*)

View file

@ -335,17 +335,29 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> mess
AvatarTraits::TraitInstanceID traitInstanceID =
QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
// XOR the incoming trait instance ID with this avatar object's personal XOR ID
// this ensures that we have separate entity instances in the local tree
// if we briefly end up with two Avatar objects for this node
// (which can occur if the shared pointer for the
// previous instance of an avatar hasn't yet gone out of scope before the
// new instance is created)
auto xoredInstanceID = AvatarTraits::xoredInstanceID(traitInstanceID, avatar->getTraitInstanceXORID());
message->readPrimitive(&traitBinarySize);
auto& processedInstanceVersion = lastProcessedVersions.getInstanceValueRef(traitType, traitInstanceID);
if (packetTraitVersion > processedInstanceVersion) {
// in order to handle re-connections to the avatar mixer when the other
if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) {
avatar->processDeletedTraitInstance(traitType, traitInstanceID);
_replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID);
avatar->processDeletedTraitInstance(traitType, xoredInstanceID);
_replicas.processDeletedTraitInstance(avatarID, traitType, xoredInstanceID);
} else {
auto traitData = message->read(traitBinarySize);
avatar->processTraitInstance(traitType, traitInstanceID, traitData);
_replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData);
avatar->processTraitInstance(traitType, xoredInstanceID, traitData);
_replicas.processTraitInstance(avatarID, traitType, xoredInstanceID, traitData);
}
processedInstanceVersion = packetTraitVersion;
} else {

View file

@ -41,7 +41,8 @@ namespace AvatarTraits {
const TraitWireSize DELETED_TRAIT_SIZE = -1;
inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination,
TraitVersion traitVersion = NULL_TRAIT_VERSION) {
TraitVersion traitVersion = NULL_TRAIT_VERSION,
TraitInstanceID xoredInstanceID = TraitInstanceID()) {
qint64 bytesWritten = 0;
bytesWritten += destination.writePrimitive(traitType);
@ -50,12 +51,28 @@ namespace AvatarTraits {
bytesWritten += destination.writePrimitive(traitVersion);
}
bytesWritten += destination.write(instanceID.toRfc4122());
if (xoredInstanceID.isNull()) {
bytesWritten += destination.write(instanceID.toRfc4122());
} else {
bytesWritten += destination.write(xoredInstanceID.toRfc4122());
}
bytesWritten += destination.writePrimitive(DELETED_TRAIT_SIZE);
return bytesWritten;
}
inline TraitInstanceID xoredInstanceID(TraitInstanceID localInstanceID, TraitInstanceID xorKeyID) {
QByteArray xoredInstanceID { NUM_BYTES_RFC4122_UUID, 0 };
auto xorKeyIDBytes = xorKeyID.toRfc4122();
auto localInstanceIDBytes = localInstanceID.toRfc4122();
for (auto i = 0; i < localInstanceIDBytes.size(); ++i) {
xoredInstanceID[i] = localInstanceIDBytes[i] ^ xorKeyIDBytes[i];
}
return QUuid::fromRfc4122(xoredInstanceID);
}
};
#endif // hifi_AvatarTraits_h

View file

@ -45,7 +45,7 @@ void ClientTraitsHandler::resetForNewMixer() {
_owningAvatar->prepareResetTraitInstances();
// reset the trait XOR ID since we're resetting for a new avatar mixer
_sessionXORID = QUuid::createUuid().toRfc4122();
_owningAvatar->cycleTraitInstanceXORID();
}
void ClientTraitsHandler::sendChangedTraitsToMixer() {
@ -100,11 +100,15 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
// since this is going to the mixer, use the XORed instance ID (to anonymize trait instance IDs
// that would typically persist across sessions)
_owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList,
AvatarTraits::NULL_TRAIT_VERSION, xorInstanceID(instanceIDValuePair.id));
AvatarTraits::NULL_TRAIT_VERSION,
AvatarTraits::xoredInstanceID(instanceIDValuePair.id,
_owningAvatar->getTraitInstanceXORID()));
} else if (!_shouldPerformInitialSend && instanceIDValuePair.value == Deleted) {
// pack delete for this trait instance
AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id,
*traitsPacketList);
*traitsPacketList, AvatarTraits::NULL_TRAIT_VERSION,
AvatarTraits::xoredInstanceID(instanceIDValuePair.id,
_owningAvatar->getTraitInstanceXORID()));
}
}
@ -118,17 +122,6 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
}
}
AvatarTraits::TraitInstanceID ClientTraitsHandler::xorInstanceID(AvatarTraits::TraitInstanceID localInstanceID) {
QByteArray xorInstanceID { NUM_BYTES_RFC4122_UUID, 0 };
auto localInstanceIDBytes = localInstanceID.toRfc4122();
for (auto i = 0; i < localInstanceIDBytes.size(); ++i) {
xorInstanceID[i] = localInstanceIDBytes[i] ^ _sessionXORID[i];
}
return QUuid::fromRfc4122(xorInstanceID);
}
void ClientTraitsHandler::processTraitOverride(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
if (sendingNode->getType() == NodeType::AvatarMixer) {
while (message->getBytesLeftToRead()) {

View file

@ -37,8 +37,6 @@ public:
void resetForNewMixer();
AvatarTraits::TraitInstanceID xorInstanceID(AvatarTraits::TraitInstanceID localInstanceID);
public slots:
void processTraitOverride(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
@ -55,8 +53,6 @@ private:
AvatarTraits::TraitVersion _currentTraitVersion { AvatarTraits::DEFAULT_TRAIT_VERSION };
AvatarTraits::TraitVersion _currentSkeletonVersion { AvatarTraits::NULL_TRAIT_VERSION };
QByteArray _sessionXORID { NUM_BYTES_RFC4122_UUID, 0};
bool _shouldPerformInitialSend { false };
bool _hasChangedTraits { false };