mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Merge pull request #13907 from birarda/feat/mixer-trait-state-reset
mark and cycle trait instances needing to be sent on mixer reconnect
This commit is contained in:
commit
dc02ff66f5
8 changed files with 87 additions and 16 deletions
|
@ -6364,7 +6364,6 @@ void Application::clearDomainOctreeDetails() {
|
|||
}
|
||||
|
||||
void Application::clearDomainAvatars() {
|
||||
getMyAvatar()->setAvatarEntityDataChanged(true); // to recreate worn entities
|
||||
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,6 @@ Avatar::~Avatar() {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_nameRectGeometryID);
|
||||
|
|
|
@ -1861,7 +1861,9 @@ qint64 AvatarData::packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice
|
|||
}
|
||||
|
||||
qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID traitInstanceID,
|
||||
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion) {
|
||||
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion,
|
||||
AvatarTraits::TraitInstanceID wireInstanceID) {
|
||||
|
||||
qint64 bytesWritten = 0;
|
||||
|
||||
bytesWritten += destination.writePrimitive(traitType);
|
||||
|
@ -1870,7 +1872,11 @@ qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTr
|
|||
bytesWritten += destination.writePrimitive(traitVersion);
|
||||
}
|
||||
|
||||
bytesWritten += destination.write(traitInstanceID.toRfc4122());
|
||||
if (!wireInstanceID.isNull()) {
|
||||
bytesWritten += destination.write(wireInstanceID.toRfc4122());
|
||||
} else {
|
||||
bytesWritten += destination.write(traitInstanceID.toRfc4122());
|
||||
}
|
||||
|
||||
if (traitType == AvatarTraits::AvatarEntity) {
|
||||
// grab a read lock on the avatar entities and check for entity data for the given ID
|
||||
|
@ -1895,6 +1901,16 @@ qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTr
|
|||
return bytesWritten;
|
||||
}
|
||||
|
||||
void AvatarData::prepareResetTraitInstances() {
|
||||
if (_clientTraitsHandler) {
|
||||
_avatarEntitiesLock.withReadLock([this]{
|
||||
foreach (auto entityID, _avatarEntityData.keys()) {
|
||||
_clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarData::processTrait(AvatarTraits::TraitType traitType, QByteArray traitBinaryData) {
|
||||
if (traitType == AvatarTraits::SkeletonModelURL) {
|
||||
// get the URL from the binary data
|
||||
|
@ -2792,7 +2808,7 @@ void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) {
|
|||
if (_clientTraitsHandler) {
|
||||
// if we have a client traits handler, flag any updated or created entities
|
||||
// so that we send changes for them next frame
|
||||
foreach (auto entityID, _avatarEntityData) {
|
||||
foreach (auto entityID, _avatarEntityData.keys()) {
|
||||
_clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -962,7 +962,10 @@ public:
|
|||
qint64 packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice& destination,
|
||||
AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION);
|
||||
qint64 packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID,
|
||||
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION);
|
||||
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION,
|
||||
AvatarTraits::TraitInstanceID wireInstanceID = AvatarTraits::TraitInstanceID());
|
||||
|
||||
void prepareResetTraitInstances();
|
||||
|
||||
void processTrait(AvatarTraits::TraitType traitType, QByteArray traitBinaryData);
|
||||
void processTraitInstance(AvatarTraits::TraitType traitType,
|
||||
|
@ -1190,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
|
||||
|
@ -1496,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*)
|
||||
|
||||
|
|
|
@ -85,7 +85,8 @@ void AvatarReplicas::processDeletedTraitInstance(const QUuid& parentID, AvatarTr
|
|||
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
||||
auto &replicas = _replicasMap[parentID];
|
||||
for (auto avatar : replicas) {
|
||||
avatar->processDeletedTraitInstance(traitType, instanceID);
|
||||
avatar->processDeletedTraitInstance(traitType,
|
||||
AvatarTraits::xoredInstanceID(instanceID, avatar->getTraitInstanceXORID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +95,9 @@ void AvatarReplicas::processTraitInstance(const QUuid& parentID, AvatarTraits::T
|
|||
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
||||
auto &replicas = _replicasMap[parentID];
|
||||
for (auto avatar : replicas) {
|
||||
avatar->processTraitInstance(traitType, instanceID, traitBinaryData);
|
||||
avatar->processTraitInstance(traitType,
|
||||
AvatarTraits::xoredInstanceID(instanceID, avatar->getTraitInstanceXORID()),
|
||||
traitBinaryData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -335,16 +338,28 @@ 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);
|
||||
avatar->processDeletedTraitInstance(traitType, xoredInstanceID);
|
||||
_replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID);
|
||||
} else {
|
||||
auto traitData = message->read(traitBinarySize);
|
||||
avatar->processTraitInstance(traitType, traitInstanceID, traitData);
|
||||
avatar->processTraitInstance(traitType, xoredInstanceID, traitData);
|
||||
_replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData);
|
||||
}
|
||||
processedInstanceVersion = packetTraitVersion;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,6 +37,15 @@ void ClientTraitsHandler::resetForNewMixer() {
|
|||
|
||||
// mark that all traits should be sent next time
|
||||
_shouldPerformInitialSend = true;
|
||||
|
||||
// reset the trait statuses
|
||||
_traitStatuses.reset();
|
||||
|
||||
// pre-fill the instanced statuses that we will need to send next frame
|
||||
_owningAvatar->prepareResetTraitInstances();
|
||||
|
||||
// reset the trait XOR ID since we're resetting for a new avatar mixer
|
||||
_owningAvatar->cycleTraitInstanceXORID();
|
||||
}
|
||||
|
||||
void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
||||
|
@ -87,11 +96,19 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
|||
|| instanceIDValuePair.value == Updated) {
|
||||
// this is a changed trait we need to send or we haven't send out trait information yet
|
||||
// ask the owning avatar to pack it
|
||||
_owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList);
|
||||
|
||||
// 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,
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,9 +30,9 @@ public:
|
|||
|
||||
void markTraitUpdated(AvatarTraits::TraitType updatedTrait)
|
||||
{ _traitStatuses[updatedTrait] = Updated; _hasChangedTraits = true; }
|
||||
void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID)
|
||||
void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID updatedInstanceID)
|
||||
{ _traitStatuses.instanceInsert(traitType, updatedInstanceID, Updated); _hasChangedTraits = true; }
|
||||
void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID)
|
||||
void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID deleteInstanceID)
|
||||
{ _traitStatuses.instanceInsert(traitType, deleteInstanceID, Deleted); _hasChangedTraits = true; }
|
||||
|
||||
void resetForNewMixer();
|
||||
|
|
Loading…
Reference in a new issue