mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 04:08:13 +02:00
Checkpoint trait-level flow control
This commit is contained in:
parent
1977180ecf
commit
3a282045ff
7 changed files with 68 additions and 4 deletions
|
@ -56,6 +56,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
||||||
packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket");
|
packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket");
|
||||||
packetReceiver.registerListener(PacketType::AvatarIdentityRequest, this, "handleAvatarIdentityRequestPacket");
|
packetReceiver.registerListener(PacketType::AvatarIdentityRequest, this, "handleAvatarIdentityRequestPacket");
|
||||||
packetReceiver.registerListener(PacketType::SetAvatarTraits, this, "queueIncomingPacket");
|
packetReceiver.registerListener(PacketType::SetAvatarTraits, this, "queueIncomingPacket");
|
||||||
|
packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck, this, "queueIncomingPacket");
|
||||||
|
|
||||||
packetReceiver.registerListenerForTypes({
|
packetReceiver.registerListenerForTypes({
|
||||||
PacketType::ReplicatedAvatarIdentity,
|
PacketType::ReplicatedAvatarIdentity,
|
||||||
|
|
|
@ -68,6 +68,9 @@ int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData
|
||||||
case PacketType::SetAvatarTraits:
|
case PacketType::SetAvatarTraits:
|
||||||
processSetTraitsMessage(*packet, slaveSharedData, *node);
|
processSetTraitsMessage(*packet, slaveSharedData, *node);
|
||||||
break;
|
break;
|
||||||
|
case PacketType::BulkAvatarTraitsAck:
|
||||||
|
processBulkAvatarTraitsAckMessage(*packet);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -179,6 +182,29 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarMixerClientData::processBulkAvatarTraitsAckMessage(ReceivedMessage& message) {
|
||||||
|
|
||||||
|
// Look up the avatar/trait data associated with this ack and update the 'last ack' list
|
||||||
|
// with it.
|
||||||
|
AvatarTraits::TraitMessageSequence seq;
|
||||||
|
message.readPrimitive(&seq);
|
||||||
|
auto& sentAvatarTraitVersions = _pendingTraitVersions.find(seq);
|
||||||
|
if (sentAvatarTraitVersions != _pendingTraitVersions.end()) {
|
||||||
|
for (auto& nodeTraitVersions : sentAvatarTraitVersions->second) {
|
||||||
|
auto& nodeId = nodeTraitVersions.first;
|
||||||
|
auto& versions = nodeTraitVersions.second;
|
||||||
|
auto simpleReceivedIt = versions.simpleCBegin();
|
||||||
|
while (simpleReceivedIt != versions.simpleCEnd()) {
|
||||||
|
auto traitType = static_cast<AvatarTraits::TraitType>(std::distance(versions.simpleCBegin(),
|
||||||
|
simpleReceivedIt));
|
||||||
|
_ackedTraitVersions[nodeId][traitType] = *simpleReceivedIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_pendingTraitVersions.erase(sentAvatarTraitVersions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AvatarMixerClientData::checkSkeletonURLAgainstWhitelist(const SlaveSharedData &slaveSharedData, Node& sendingNode,
|
void AvatarMixerClientData::checkSkeletonURLAgainstWhitelist(const SlaveSharedData &slaveSharedData, Node& sendingNode,
|
||||||
AvatarTraits::TraitVersion traitVersion) {
|
AvatarTraits::TraitVersion traitVersion) {
|
||||||
const auto& whitelist = slaveSharedData.skeletonURLWhitelist;
|
const auto& whitelist = slaveSharedData.skeletonURLWhitelist;
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
AvatarMixerClientData(const QUuid& nodeID, Node::LocalID nodeLocalID);
|
AvatarMixerClientData(const QUuid& nodeID, Node::LocalID nodeLocalID);
|
||||||
virtual ~AvatarMixerClientData() {}
|
virtual ~AvatarMixerClientData() {}
|
||||||
using HRCTime = p_high_resolution_clock::time_point;
|
using HRCTime = p_high_resolution_clock::time_point;
|
||||||
|
using NodeTraitVersions = std::unordered_map<Node::LocalID, AvatarTraits::TraitVersions>;
|
||||||
|
|
||||||
int parseData(ReceivedMessage& message) override;
|
int parseData(ReceivedMessage& message) override;
|
||||||
AvatarData& getAvatar() { return *_avatar; }
|
AvatarData& getAvatar() { return *_avatar; }
|
||||||
|
@ -124,6 +125,7 @@ public:
|
||||||
int processPackets(const SlaveSharedData& slaveSharedData); // returns number of packets processed
|
int processPackets(const SlaveSharedData& slaveSharedData); // returns number of packets processed
|
||||||
|
|
||||||
void processSetTraitsMessage(ReceivedMessage& message, const SlaveSharedData& slaveSharedData, Node& sendingNode);
|
void processSetTraitsMessage(ReceivedMessage& message, const SlaveSharedData& slaveSharedData, Node& sendingNode);
|
||||||
|
void processBulkAvatarTraitsAckMessage(ReceivedMessage& message);
|
||||||
void checkSkeletonURLAgainstWhitelist(const SlaveSharedData& slaveSharedData, Node& sendingNode,
|
void checkSkeletonURLAgainstWhitelist(const SlaveSharedData& slaveSharedData, Node& sendingNode,
|
||||||
AvatarTraits::TraitVersion traitVersion);
|
AvatarTraits::TraitVersion traitVersion);
|
||||||
|
|
||||||
|
@ -138,7 +140,14 @@ public:
|
||||||
void setLastOtherAvatarTraitsSendPoint(Node::LocalID otherAvatar, TraitsCheckTimestamp sendPoint)
|
void setLastOtherAvatarTraitsSendPoint(Node::LocalID otherAvatar, TraitsCheckTimestamp sendPoint)
|
||||||
{ _lastSentTraitsTimestamps[otherAvatar] = sendPoint; }
|
{ _lastSentTraitsTimestamps[otherAvatar] = sendPoint; }
|
||||||
|
|
||||||
|
AvatarTraits::TraitMessageSequence getTraitsMessageSequence() const { return _currentTraitsMessageSequence; }
|
||||||
|
AvatarTraits::TraitMessageSequence nextTraitsMessageSequence() { return ++_currentTraitsMessageSequence; }
|
||||||
|
AvatarTraits::TraitVersions& getPendingTraitVersions(AvatarTraits::TraitMessageSequence seq, Node::LocalID otherId) {
|
||||||
|
return _pendingTraitVersions[seq][otherId];
|
||||||
|
}
|
||||||
|
|
||||||
AvatarTraits::TraitVersions& getLastSentTraitVersions(Node::LocalID otherAvatar) { return _sentTraitVersions[otherAvatar]; }
|
AvatarTraits::TraitVersions& getLastSentTraitVersions(Node::LocalID otherAvatar) { return _sentTraitVersions[otherAvatar]; }
|
||||||
|
AvatarTraits::TraitVersions& getLastAckedTraitVersions(Node::LocalID otherAvatar) { return _ackedTraitVersions[otherAvatar]; }
|
||||||
|
|
||||||
void resetSentTraitData(Node::LocalID nodeID);
|
void resetSentTraitData(Node::LocalID nodeID);
|
||||||
|
|
||||||
|
@ -183,8 +192,13 @@ private:
|
||||||
AvatarTraits::TraitVersions _lastReceivedTraitVersions;
|
AvatarTraits::TraitVersions _lastReceivedTraitVersions;
|
||||||
TraitsCheckTimestamp _lastReceivedTraitsChange;
|
TraitsCheckTimestamp _lastReceivedTraitsChange;
|
||||||
|
|
||||||
|
AvatarTraits::TraitMessageSequence _currentTraitsMessageSequence{ 0 };
|
||||||
|
|
||||||
|
std::unordered_map<AvatarTraits::TraitMessageSequence, NodeTraitVersions> _pendingTraitVersions;
|
||||||
|
|
||||||
std::unordered_map<Node::LocalID, TraitsCheckTimestamp> _lastSentTraitsTimestamps;
|
std::unordered_map<Node::LocalID, TraitsCheckTimestamp> _lastSentTraitsTimestamps;
|
||||||
std::unordered_map<Node::LocalID, AvatarTraits::TraitVersions> _sentTraitVersions;
|
NodeTraitVersions _sentTraitVersions;
|
||||||
|
NodeTraitVersions _ackedTraitVersions;
|
||||||
|
|
||||||
std::atomic_bool _isIgnoreRadiusEnabled { false };
|
std::atomic_bool _isIgnoreRadiusEnabled { false };
|
||||||
};
|
};
|
||||||
|
|
|
@ -103,6 +103,7 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis
|
||||||
|
|
||||||
// compare trait versions so we can see what exactly needs to go out
|
// compare trait versions so we can see what exactly needs to go out
|
||||||
auto& lastSentVersions = listeningNodeData->getLastSentTraitVersions(otherNodeLocalID);
|
auto& lastSentVersions = listeningNodeData->getLastSentTraitVersions(otherNodeLocalID);
|
||||||
|
auto& lastAckedVersions = listeningNodeData->getLastAckedTraitVersions(otherNodeLocalID);
|
||||||
const auto& lastReceivedVersions = sendingNodeData->getLastReceivedTraitVersions();
|
const auto& lastReceivedVersions = sendingNodeData->getLastReceivedTraitVersions();
|
||||||
|
|
||||||
auto simpleReceivedIt = lastReceivedVersions.simpleCBegin();
|
auto simpleReceivedIt = lastReceivedVersions.simpleCBegin();
|
||||||
|
@ -112,13 +113,18 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis
|
||||||
|
|
||||||
auto lastReceivedVersion = *simpleReceivedIt;
|
auto lastReceivedVersion = *simpleReceivedIt;
|
||||||
auto& lastSentVersionRef = lastSentVersions[traitType];
|
auto& lastSentVersionRef = lastSentVersions[traitType];
|
||||||
|
auto& lastAckedVersionRef = lastAckedVersions[traitType];
|
||||||
|
|
||||||
if (lastReceivedVersions[traitType] > lastSentVersionRef) {
|
// hold sending more traits until we've been acked that the last one we sent was received
|
||||||
|
if (lastAckedVersionRef == lastSentVersionRef && lastReceivedVersions[traitType] > lastSentVersionRef) {
|
||||||
// there is an update to this trait, add it to the traits packet
|
// there is an update to this trait, add it to the traits packet
|
||||||
bytesWritten += sendingAvatar->packTrait(traitType, traitsPacketList, lastReceivedVersion);
|
bytesWritten += sendingAvatar->packTrait(traitType, traitsPacketList, lastReceivedVersion);
|
||||||
|
|
||||||
// update the last sent version
|
// update the last sent version
|
||||||
lastSentVersionRef = lastReceivedVersion;
|
lastSentVersionRef = lastReceivedVersion;
|
||||||
|
// Remember which versions we sent in this particular packet
|
||||||
|
// so we can verify when it's acked.
|
||||||
|
auto& pendingTraitVersions = listeningNodeData->getPendingTraitVersions(listeningNodeData->getTraitsMessageSequence(), otherNodeLocalID);
|
||||||
|
pendingTraitVersions[traitType] = lastReceivedVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
++simpleReceivedIt;
|
++simpleReceivedIt;
|
||||||
|
@ -419,6 +425,8 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
int remainingAvatars = (int)sortedAvatars.size();
|
int remainingAvatars = (int)sortedAvatars.size();
|
||||||
auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true);
|
auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true);
|
||||||
|
traitsPacketList->writePrimitive(nodeData->nextTraitsMessageSequence());
|
||||||
|
|
||||||
auto avatarPacket = NLPacket::create(PacketType::BulkAvatarData);
|
auto avatarPacket = NLPacket::create(PacketType::BulkAvatarData);
|
||||||
const int avatarPacketCapacity = avatarPacket->getPayloadCapacity();
|
const int avatarPacketCapacity = avatarPacket->getPayloadCapacity();
|
||||||
int avatarSpaceAvailable = avatarPacketCapacity;
|
int avatarSpaceAvailable = avatarPacketCapacity;
|
||||||
|
|
|
@ -328,6 +328,17 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||||
|
AvatarTraits::TraitMessageSequence seq;
|
||||||
|
|
||||||
|
message->readPrimitive(&seq);
|
||||||
|
|
||||||
|
// we have a mixer to send to, setup our set traits packet
|
||||||
|
auto traitsAckPacket = NLPacket::create(PacketType::BulkAvatarTraitsAck, sizeof(AvatarTraits::TraitMessageSequence), true);
|
||||||
|
traitsAckPacket->writePrimitive(seq);
|
||||||
|
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);
|
||||||
|
nodeList->sendPacket(std::move(traitsAckPacket), *avatarMixer);
|
||||||
|
|
||||||
|
|
||||||
while (message->getBytesLeftToRead()) {
|
while (message->getBytesLeftToRead()) {
|
||||||
// read the avatar ID to figure out which avatar this is for
|
// read the avatar ID to figure out which avatar this is for
|
||||||
|
|
|
@ -41,6 +41,10 @@ namespace AvatarTraits {
|
||||||
const TraitWireSize DELETED_TRAIT_SIZE = -1;
|
const TraitWireSize DELETED_TRAIT_SIZE = -1;
|
||||||
const TraitWireSize MAXIMUM_TRAIT_SIZE = INT16_MAX;
|
const TraitWireSize MAXIMUM_TRAIT_SIZE = INT16_MAX;
|
||||||
|
|
||||||
|
using TraitMessageSequence = int64_t;
|
||||||
|
const TraitMessageSequence FIRST_TRAIT_SEQUENCE = 0;
|
||||||
|
const TraitMessageSequence MAX_TRAIT_SEQUENCE = INT64_MAX;
|
||||||
|
|
||||||
inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination,
|
inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination,
|
||||||
TraitVersion traitVersion = NULL_TRAIT_VERSION) {
|
TraitVersion traitVersion = NULL_TRAIT_VERSION) {
|
||||||
qint64 bytesWritten = 0;
|
qint64 bytesWritten = 0;
|
||||||
|
|
|
@ -133,7 +133,7 @@ public:
|
||||||
EntityQueryInitialResultsComplete,
|
EntityQueryInitialResultsComplete,
|
||||||
BulkAvatarTraits,
|
BulkAvatarTraits,
|
||||||
AudioSoloRequest,
|
AudioSoloRequest,
|
||||||
|
BulkAvatarTraitsAck,
|
||||||
NUM_PACKET_TYPE
|
NUM_PACKET_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue