mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 18:41:10 +02:00
Merge branch 'master' into avatar-mixer-entities-stats
This commit is contained in:
commit
1245abbb53
20 changed files with 229 additions and 49 deletions
|
@ -504,7 +504,7 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre
|
||||||
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
||||||
float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition);
|
float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition);
|
||||||
|
|
||||||
float gain = 1.0f;
|
float gain = masterListenerGain;
|
||||||
if (!isSoloing) {
|
if (!isSoloing) {
|
||||||
gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho);
|
gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -19,9 +19,8 @@
|
||||||
|
|
||||||
#include "AvatarMixerSlave.h"
|
#include "AvatarMixerSlave.h"
|
||||||
|
|
||||||
AvatarMixerClientData::AvatarMixerClientData(const QUuid& nodeID, Node::LocalID nodeLocalID) :
|
AvatarMixerClientData::AvatarMixerClientData(const QUuid& nodeID, Node::LocalID nodeLocalID) :
|
||||||
NodeData(nodeID, nodeLocalID)
|
NodeData(nodeID, nodeLocalID) {
|
||||||
{
|
|
||||||
// in case somebody calls getSessionUUID on the AvatarData instance, make sure it has the right ID
|
// in case somebody calls getSessionUUID on the AvatarData instance, make sure it has the right ID
|
||||||
_avatar->setID(nodeID);
|
_avatar->setID(nodeID);
|
||||||
}
|
}
|
||||||
|
@ -68,6 +67,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();
|
||||||
}
|
}
|
||||||
|
@ -79,12 +81,11 @@ int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData
|
||||||
}
|
}
|
||||||
|
|
||||||
int AvatarMixerClientData::parseData(ReceivedMessage& message) {
|
int AvatarMixerClientData::parseData(ReceivedMessage& message) {
|
||||||
|
|
||||||
// pull the sequence number from the data first
|
// pull the sequence number from the data first
|
||||||
uint16_t sequenceNumber;
|
uint16_t sequenceNumber;
|
||||||
|
|
||||||
message.readPrimitive(&sequenceNumber);
|
message.readPrimitive(&sequenceNumber);
|
||||||
|
|
||||||
if (sequenceNumber < _lastReceivedSequenceNumber && _lastReceivedSequenceNumber != UINT16_MAX) {
|
if (sequenceNumber < _lastReceivedSequenceNumber && _lastReceivedSequenceNumber != UINT16_MAX) {
|
||||||
incrementNumOutOfOrderSends();
|
incrementNumOutOfOrderSends();
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,8 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
||||||
const SlaveSharedData& slaveSharedData, Node& sendingNode) {
|
const SlaveSharedData& slaveSharedData,
|
||||||
|
Node& sendingNode) {
|
||||||
// pull the trait version from the message
|
// pull the trait version from the message
|
||||||
AvatarTraits::TraitVersion packetTraitVersion;
|
AvatarTraits::TraitVersion packetTraitVersion;
|
||||||
message.readPrimitive(&packetTraitVersion);
|
message.readPrimitive(&packetTraitVersion);
|
||||||
|
@ -134,7 +136,7 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
||||||
AvatarTraits::TraitInstanceID instanceID = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
AvatarTraits::TraitInstanceID instanceID = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
if (message.getBytesLeftToRead() == 0) {
|
if (message.getBytesLeftToRead() == 0) {
|
||||||
qWarning () << "Received an instanced trait with no size from" << message.getSenderSockAddr();
|
qWarning() << "Received an instanced trait with no size from" << message.getSenderSockAddr();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +144,8 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
||||||
message.readPrimitive(&traitSize);
|
message.readPrimitive(&traitSize);
|
||||||
|
|
||||||
if (traitSize < -1 || traitSize > message.getBytesLeftToRead()) {
|
if (traitSize < -1 || traitSize > message.getBytesLeftToRead()) {
|
||||||
qWarning() << "Refusing to process instanced trait of size" << traitSize << "from" << message.getSenderSockAddr();
|
qWarning() << "Refusing to process instanced trait of size" << traitSize << "from"
|
||||||
|
<< message.getSenderSockAddr();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +172,8 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
||||||
message.seek(message.getPosition() + traitSize);
|
message.seek(message.getPosition() + traitSize);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Refusing to process traits packet with instanced trait of unprocessable type from" << message.getSenderSockAddr();
|
qWarning() << "Refusing to process traits packet with instanced trait of unprocessable type from"
|
||||||
|
<< message.getSenderSockAddr();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +184,61 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarMixerClientData::checkSkeletonURLAgainstWhitelist(const SlaveSharedData &slaveSharedData, Node& sendingNode,
|
void AvatarMixerClientData::processBulkAvatarTraitsAckMessage(ReceivedMessage& message) {
|
||||||
|
// Avatar Traits flow control marks each outgoing avatar traits packet with a
|
||||||
|
// sequence number. The mixer caches the traits sent in the traits packet.
|
||||||
|
// Until an ack with the sequence number comes back, all updates to _traits
|
||||||
|
// in that packet_ are ignored. Updates to traits not in that packet will
|
||||||
|
// be sent.
|
||||||
|
|
||||||
|
// 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 = _perNodePendingTraitVersions.find(seq);
|
||||||
|
if (sentAvatarTraitVersions != _perNodePendingTraitVersions.end()) {
|
||||||
|
for (auto& perNodeTraitVersions : sentAvatarTraitVersions->second) {
|
||||||
|
auto& nodeId = perNodeTraitVersions.first;
|
||||||
|
auto& traitVersions = perNodeTraitVersions.second;
|
||||||
|
// For each trait that was sent in the traits packet,
|
||||||
|
// update the 'acked' trait version. Traits not
|
||||||
|
// sent in the traits packet keep their version.
|
||||||
|
|
||||||
|
// process simple traits
|
||||||
|
auto simpleReceivedIt = traitVersions.simpleCBegin();
|
||||||
|
while (simpleReceivedIt != traitVersions.simpleCEnd()) {
|
||||||
|
auto traitType = static_cast<AvatarTraits::TraitType>(std::distance(traitVersions.simpleCBegin(), simpleReceivedIt));
|
||||||
|
_perNodeAckedTraitVersions[nodeId][traitType] = *simpleReceivedIt;
|
||||||
|
simpleReceivedIt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process instanced traits
|
||||||
|
auto instancedSentIt = traitVersions.instancedCBegin();
|
||||||
|
while (instancedSentIt != traitVersions.instancedCEnd()) {
|
||||||
|
auto traitType = instancedSentIt->traitType;
|
||||||
|
|
||||||
|
for (auto& sentInstance : instancedSentIt->instances) {
|
||||||
|
auto instanceID = sentInstance.id;
|
||||||
|
const auto sentVersion = sentInstance.value;
|
||||||
|
_perNodeAckedTraitVersions[nodeId].instanceInsert(traitType, instanceID, sentVersion);
|
||||||
|
}
|
||||||
|
instancedSentIt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_perNodePendingTraitVersions.erase(sentAvatarTraitVersions);
|
||||||
|
} else {
|
||||||
|
// This can happen either the BulkAvatarTraits was sent with no simple traits,
|
||||||
|
// or if the avatar mixer restarts while there are pending
|
||||||
|
// BulkAvatarTraits messages in-flight.
|
||||||
|
if (seq > getTraitsMessageSequence()) {
|
||||||
|
qWarning() << "Received BulkAvatarTraitsAck with future seq (potential avatar mixer restart) " << seq << " from "
|
||||||
|
<< message.getSenderSockAddr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarMixerClientData::checkSkeletonURLAgainstWhitelist(const SlaveSharedData& slaveSharedData,
|
||||||
|
Node& sendingNode,
|
||||||
AvatarTraits::TraitVersion traitVersion) {
|
AvatarTraits::TraitVersion traitVersion) {
|
||||||
const auto& whitelist = slaveSharedData.skeletonURLWhitelist;
|
const auto& whitelist = slaveSharedData.skeletonURLWhitelist;
|
||||||
|
|
||||||
|
@ -282,14 +340,14 @@ void AvatarMixerClientData::removeFromRadiusIgnoringSet(const QUuid& other) {
|
||||||
|
|
||||||
void AvatarMixerClientData::resetSentTraitData(Node::LocalID nodeLocalID) {
|
void AvatarMixerClientData::resetSentTraitData(Node::LocalID nodeLocalID) {
|
||||||
_lastSentTraitsTimestamps[nodeLocalID] = TraitsCheckTimestamp();
|
_lastSentTraitsTimestamps[nodeLocalID] = TraitsCheckTimestamp();
|
||||||
_sentTraitVersions[nodeLocalID].reset();
|
_perNodeSentTraitVersions[nodeLocalID].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarMixerClientData::readViewFrustumPacket(const QByteArray& message) {
|
void AvatarMixerClientData::readViewFrustumPacket(const QByteArray& message) {
|
||||||
_currentViewFrustums.clear();
|
_currentViewFrustums.clear();
|
||||||
|
|
||||||
auto sourceBuffer = reinterpret_cast<const unsigned char*>(message.constData());
|
auto sourceBuffer = reinterpret_cast<const unsigned char*>(message.constData());
|
||||||
|
|
||||||
uint8_t numFrustums = 0;
|
uint8_t numFrustums = 0;
|
||||||
memcpy(&numFrustums, sourceBuffer, sizeof(numFrustums));
|
memcpy(&numFrustums, sourceBuffer, sizeof(numFrustums));
|
||||||
sourceBuffer += sizeof(numFrustums);
|
sourceBuffer += sizeof(numFrustums);
|
||||||
|
@ -339,5 +397,5 @@ void AvatarMixerClientData::cleanupKilledNode(const QUuid&, Node::LocalID nodeLo
|
||||||
removeLastBroadcastSequenceNumber(nodeLocalID);
|
removeLastBroadcastSequenceNumber(nodeLocalID);
|
||||||
removeLastBroadcastTime(nodeLocalID);
|
removeLastBroadcastTime(nodeLocalID);
|
||||||
_lastSentTraitsTimestamps.erase(nodeLocalID);
|
_lastSentTraitsTimestamps.erase(nodeLocalID);
|
||||||
_sentTraitVersions.erase(nodeLocalID);
|
_perNodeSentTraitVersions.erase(nodeLocalID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,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 PerNodeTraitVersions = 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; }
|
||||||
|
@ -130,6 +131,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);
|
||||||
|
|
||||||
|
@ -144,7 +146,14 @@ public:
|
||||||
void setLastOtherAvatarTraitsSendPoint(Node::LocalID otherAvatar, TraitsCheckTimestamp sendPoint)
|
void setLastOtherAvatarTraitsSendPoint(Node::LocalID otherAvatar, TraitsCheckTimestamp sendPoint)
|
||||||
{ _lastSentTraitsTimestamps[otherAvatar] = sendPoint; }
|
{ _lastSentTraitsTimestamps[otherAvatar] = sendPoint; }
|
||||||
|
|
||||||
AvatarTraits::TraitVersions& getLastSentTraitVersions(Node::LocalID otherAvatar) { return _sentTraitVersions[otherAvatar]; }
|
AvatarTraits::TraitMessageSequence getTraitsMessageSequence() const { return _currentTraitsMessageSequence; }
|
||||||
|
AvatarTraits::TraitMessageSequence nextTraitsMessageSequence() { return ++_currentTraitsMessageSequence; }
|
||||||
|
AvatarTraits::TraitVersions& getPendingTraitVersions(AvatarTraits::TraitMessageSequence seq, Node::LocalID otherId) {
|
||||||
|
return _perNodePendingTraitVersions[seq][otherId];
|
||||||
|
}
|
||||||
|
|
||||||
|
AvatarTraits::TraitVersions& getLastSentTraitVersions(Node::LocalID otherAvatar) { return _perNodeSentTraitVersions[otherAvatar]; }
|
||||||
|
AvatarTraits::TraitVersions& getLastAckedTraitVersions(Node::LocalID otherAvatar) { return _perNodeAckedTraitVersions[otherAvatar]; }
|
||||||
|
|
||||||
void resetSentTraitData(Node::LocalID nodeID);
|
void resetSentTraitData(Node::LocalID nodeID);
|
||||||
|
|
||||||
|
@ -190,8 +199,27 @@ private:
|
||||||
AvatarTraits::TraitVersions _lastReceivedTraitVersions;
|
AvatarTraits::TraitVersions _lastReceivedTraitVersions;
|
||||||
TraitsCheckTimestamp _lastReceivedTraitsChange;
|
TraitsCheckTimestamp _lastReceivedTraitsChange;
|
||||||
|
|
||||||
|
AvatarTraits::TraitMessageSequence _currentTraitsMessageSequence{ 0 };
|
||||||
|
|
||||||
|
// Cache of trait versions sent in a given packet (indexed by sequence number)
|
||||||
|
// When an ack is received, the sequence number in the ack is used to look up
|
||||||
|
// the sent trait versions and they are copied to _perNodeAckedTraitVersions.
|
||||||
|
// We remember the data in _perNodePendingTraitVersions instead of requiring
|
||||||
|
// the client to return all of the versions for each trait it received in a given packet,
|
||||||
|
// reducing the size of the ack packet.
|
||||||
|
std::unordered_map<AvatarTraits::TraitMessageSequence, PerNodeTraitVersions> _perNodePendingTraitVersions;
|
||||||
|
|
||||||
|
// Versions of traits that have been acked, which will be compared to incoming
|
||||||
|
// trait updates. Incoming updates going to a given node will be ignored if
|
||||||
|
// the ack for the previous packet (containing those versions) has not been
|
||||||
|
// received.
|
||||||
|
PerNodeTraitVersions _perNodeAckedTraitVersions;
|
||||||
|
|
||||||
std::unordered_map<Node::LocalID, TraitsCheckTimestamp> _lastSentTraitsTimestamps;
|
std::unordered_map<Node::LocalID, TraitsCheckTimestamp> _lastSentTraitsTimestamps;
|
||||||
std::unordered_map<Node::LocalID, AvatarTraits::TraitVersions> _sentTraitVersions;
|
|
||||||
|
// cache of traits sent to a node which are compared to incoming traits to
|
||||||
|
// prevent sending traits that have already been sent.
|
||||||
|
PerNodeTraitVersions _perNodeSentTraitVersions;
|
||||||
|
|
||||||
std::atomic_bool _isIgnoreRadiusEnabled { false };
|
std::atomic_bool _isIgnoreRadiusEnabled { false };
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,10 +81,31 @@ int AvatarMixerSlave::sendIdentityPacket(NLPacketList& packetList, const AvatarM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qint64 AvatarMixerSlave::addTraitsNodeHeader(AvatarMixerClientData* listeningNodeData,
|
||||||
|
const AvatarMixerClientData* sendingNodeData,
|
||||||
|
NLPacketList& traitsPacketList,
|
||||||
|
qint64 bytesWritten) {
|
||||||
|
if (bytesWritten == 0) {
|
||||||
|
if (traitsPacketList.getNumPackets() == 0) {
|
||||||
|
// This is the beginning of the traits packet, write out the sequence number.
|
||||||
|
bytesWritten += traitsPacketList.writePrimitive(listeningNodeData->nextTraitsMessageSequence());
|
||||||
|
}
|
||||||
|
// This is the beginning of the traits for a node, write out the node id
|
||||||
|
bytesWritten += traitsPacketList.write(sendingNodeData->getNodeID().toRfc4122());
|
||||||
|
}
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* listeningNodeData,
|
qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* listeningNodeData,
|
||||||
const AvatarMixerClientData* sendingNodeData,
|
const AvatarMixerClientData* sendingNodeData,
|
||||||
NLPacketList& traitsPacketList) {
|
NLPacketList& traitsPacketList) {
|
||||||
|
|
||||||
|
// Avatar Traits flow control marks each outgoing avatar traits packet with a
|
||||||
|
// sequence number. The mixer caches the traits sent in the traits packet.
|
||||||
|
// Until an ack with the sequence number comes back, all updates to _traits
|
||||||
|
// in that packet_ are ignored. Updates to traits not in that packet will
|
||||||
|
// be sent.
|
||||||
|
|
||||||
auto otherNodeLocalID = sendingNodeData->getNodeLocalID();
|
auto otherNodeLocalID = sendingNodeData->getNodeLocalID();
|
||||||
|
|
||||||
// Perform a simple check with two server clock time points
|
// Perform a simple check with two server clock time points
|
||||||
|
@ -97,13 +118,11 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis
|
||||||
if (timeOfLastTraitsChange > timeOfLastTraitsSent) {
|
if (timeOfLastTraitsChange > timeOfLastTraitsSent) {
|
||||||
// there is definitely new traits data to send
|
// there is definitely new traits data to send
|
||||||
|
|
||||||
// add the avatar ID to mark the beginning of traits for this avatar
|
|
||||||
bytesWritten += traitsPacketList.write(sendingNodeData->getNodeID().toRfc4122());
|
|
||||||
|
|
||||||
auto sendingAvatar = sendingNodeData->getAvatarSharedPointer();
|
auto sendingAvatar = sendingNodeData->getAvatarSharedPointer();
|
||||||
|
|
||||||
// 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 +131,19 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis
|
||||||
simpleReceivedIt));
|
simpleReceivedIt));
|
||||||
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 (lastSentVersionRef == lastAckedVersionRef && lastReceivedVersions[traitType] > lastSentVersionRef) {
|
||||||
|
bytesWritten += addTraitsNodeHeader(listeningNodeData, sendingNodeData, traitsPacketList, bytesWritten);
|
||||||
// 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;
|
||||||
|
@ -131,6 +156,7 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis
|
||||||
|
|
||||||
// get or create the sent trait versions for this trait type
|
// get or create the sent trait versions for this trait type
|
||||||
auto& sentIDValuePairs = lastSentVersions.getInstanceIDValuePairs(traitType);
|
auto& sentIDValuePairs = lastSentVersions.getInstanceIDValuePairs(traitType);
|
||||||
|
auto& ackIDValuePairs = lastAckedVersions.getInstanceIDValuePairs(traitType);
|
||||||
|
|
||||||
// enumerate each received instance
|
// enumerate each received instance
|
||||||
for (auto& receivedInstance : instancedReceivedIt->instances) {
|
for (auto& receivedInstance : instancedReceivedIt->instances) {
|
||||||
|
@ -148,8 +174,18 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis
|
||||||
{
|
{
|
||||||
return sentInstance.id == instanceID;
|
return sentInstance.id == instanceID;
|
||||||
});
|
});
|
||||||
|
// look for existing acked version for this instance
|
||||||
|
auto ackedInstanceIt = std::find_if(ackIDValuePairs.begin(), ackIDValuePairs.end(),
|
||||||
|
[instanceID](auto& ackInstance) { return ackInstance.id == instanceID; });
|
||||||
|
|
||||||
|
// if we have a sent version, then we must have an acked instance of the same trait with the same
|
||||||
|
// version to go on, otherwise we drop the received trait
|
||||||
|
if (sentInstanceIt != sentIDValuePairs.end() &&
|
||||||
|
(ackedInstanceIt == ackIDValuePairs.end() || sentInstanceIt->value != ackedInstanceIt->value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!isDeleted && (sentInstanceIt == sentIDValuePairs.end() || receivedVersion > sentInstanceIt->value)) {
|
if (!isDeleted && (sentInstanceIt == sentIDValuePairs.end() || receivedVersion > sentInstanceIt->value)) {
|
||||||
|
bytesWritten += addTraitsNodeHeader(listeningNodeData, sendingNodeData, traitsPacketList, bytesWritten);
|
||||||
|
|
||||||
// this instance version exists and has never been sent or is newer so we need to send it
|
// this instance version exists and has never been sent or is newer so we need to send it
|
||||||
bytesWritten += sendingAvatar->packTraitInstance(traitType, instanceID, traitsPacketList, receivedVersion);
|
bytesWritten += sendingAvatar->packTraitInstance(traitType, instanceID, traitsPacketList, receivedVersion);
|
||||||
|
@ -159,22 +195,35 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis
|
||||||
} else {
|
} else {
|
||||||
sentIDValuePairs.emplace_back(instanceID, receivedVersion);
|
sentIDValuePairs.emplace_back(instanceID, receivedVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& pendingTraitVersions =
|
||||||
|
listeningNodeData->getPendingTraitVersions(listeningNodeData->getTraitsMessageSequence(),
|
||||||
|
otherNodeLocalID);
|
||||||
|
pendingTraitVersions.instanceInsert(traitType, instanceID, receivedVersion);
|
||||||
|
|
||||||
} else if (isDeleted && sentInstanceIt != sentIDValuePairs.end() && absoluteReceivedVersion > sentInstanceIt->value) {
|
} else if (isDeleted && sentInstanceIt != sentIDValuePairs.end() && absoluteReceivedVersion > sentInstanceIt->value) {
|
||||||
|
bytesWritten += addTraitsNodeHeader(listeningNodeData, sendingNodeData, traitsPacketList, bytesWritten);
|
||||||
|
|
||||||
// this instance version was deleted and we haven't sent the delete to this client yet
|
// this instance version was deleted and we haven't sent the delete to this client yet
|
||||||
bytesWritten += AvatarTraits::packInstancedTraitDelete(traitType, instanceID, traitsPacketList, absoluteReceivedVersion);
|
bytesWritten += AvatarTraits::packInstancedTraitDelete(traitType, instanceID, traitsPacketList, absoluteReceivedVersion);
|
||||||
|
|
||||||
// update the last sent version for this trait instance to the absolute value of the deleted version
|
// update the last sent version for this trait instance to the absolute value of the deleted version
|
||||||
sentInstanceIt->value = absoluteReceivedVersion;
|
sentInstanceIt->value = absoluteReceivedVersion;
|
||||||
|
|
||||||
|
auto& pendingTraitVersions =
|
||||||
|
listeningNodeData->getPendingTraitVersions(listeningNodeData->getTraitsMessageSequence(),
|
||||||
|
otherNodeLocalID);
|
||||||
|
pendingTraitVersions.instanceInsert(traitType, instanceID, absoluteReceivedVersion);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++instancedReceivedIt;
|
++instancedReceivedIt;
|
||||||
}
|
}
|
||||||
|
if (bytesWritten) {
|
||||||
// write a null trait type to mark the end of trait data for this avatar
|
// write a null trait type to mark the end of trait data for this avatar
|
||||||
bytesWritten += traitsPacketList.writePrimitive(AvatarTraits::NullTrait);
|
bytesWritten += traitsPacketList.writePrimitive(AvatarTraits::NullTrait);
|
||||||
|
}
|
||||||
// since we send all traits for this other avatar, update the time of last traits sent
|
// since we send all traits for this other avatar, update the time of last traits sent
|
||||||
// to match the time of last traits change
|
// to match the time of last traits change
|
||||||
listeningNodeData->setLastOtherAvatarTraitsSendPoint(otherNodeLocalID, timeOfLastTraitsChange);
|
listeningNodeData->setLastOtherAvatarTraitsSendPoint(otherNodeLocalID, timeOfLastTraitsChange);
|
||||||
|
@ -420,6 +469,7 @@ 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);
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -114,6 +114,11 @@ private:
|
||||||
int sendIdentityPacket(NLPacketList& packet, const AvatarMixerClientData* nodeData, const Node& destinationNode);
|
int sendIdentityPacket(NLPacketList& packet, const AvatarMixerClientData* nodeData, const Node& destinationNode);
|
||||||
int sendReplicatedIdentityPacket(const Node& agentNode, const AvatarMixerClientData* nodeData, const Node& destinationNode);
|
int sendReplicatedIdentityPacket(const Node& agentNode, const AvatarMixerClientData* nodeData, const Node& destinationNode);
|
||||||
|
|
||||||
|
qint64 addTraitsNodeHeader(AvatarMixerClientData* listeningNodeData,
|
||||||
|
const AvatarMixerClientData* sendingNodeData,
|
||||||
|
NLPacketList& traitsPacketList,
|
||||||
|
qint64 bytesWritten);
|
||||||
|
|
||||||
qint64 addChangedTraitsToBulkPacket(AvatarMixerClientData* listeningNodeData,
|
qint64 addChangedTraitsToBulkPacket(AvatarMixerClientData* listeningNodeData,
|
||||||
const AvatarMixerClientData* sendingNodeData,
|
const AvatarMixerClientData* sendingNodeData,
|
||||||
NLPacketList& traitsPacketList);
|
NLPacketList& traitsPacketList);
|
||||||
|
|
|
@ -2060,7 +2060,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
properties["avatar_ping"] = avatarMixerNode ? avatarMixerNode->getPingMs() : -1;
|
properties["avatar_ping"] = avatarMixerNode ? avatarMixerNode->getPingMs() : -1;
|
||||||
properties["asset_ping"] = assetServerNode ? assetServerNode->getPingMs() : -1;
|
properties["asset_ping"] = assetServerNode ? assetServerNode->getPingMs() : -1;
|
||||||
properties["messages_ping"] = messagesMixerNode ? messagesMixerNode->getPingMs() : -1;
|
properties["messages_ping"] = messagesMixerNode ? messagesMixerNode->getPingMs() : -1;
|
||||||
properties["atp_in_kbps"] = messagesMixerNode ? assetServerNode->getInboundKbps() : 0.0f;
|
properties["atp_in_kbps"] = assetServerNode ? assetServerNode->getInboundKbps() : 0.0f;
|
||||||
|
|
||||||
auto loadingRequests = ResourceCache::getLoadingRequests();
|
auto loadingRequests = ResourceCache::getLoadingRequests();
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,6 @@ void addAvatarEntities(const QVariantList& avatarEntities) {
|
||||||
entityProperties.setParentID(myNodeID);
|
entityProperties.setParentID(myNodeID);
|
||||||
entityProperties.setEntityHostType(entity::HostType::AVATAR);
|
entityProperties.setEntityHostType(entity::HostType::AVATAR);
|
||||||
entityProperties.setOwningAvatarID(myNodeID);
|
entityProperties.setOwningAvatarID(myNodeID);
|
||||||
entityProperties.setSimulationOwner(myNodeID, AVATAR_ENTITY_SIMULATION_PRIORITY);
|
|
||||||
entityProperties.markAllChanged();
|
entityProperties.markAllChanged();
|
||||||
|
|
||||||
EntityItemID id = EntityItemID(QUuid::createUuid());
|
EntityItemID id = EntityItemID(QUuid::createUuid());
|
||||||
|
|
|
@ -27,6 +27,9 @@ Base3DOverlay::Base3DOverlay() :
|
||||||
_drawInFront(false),
|
_drawInFront(false),
|
||||||
_drawHUDLayer(false)
|
_drawHUDLayer(false)
|
||||||
{
|
{
|
||||||
|
// HACK: queryAACube stuff not actually relevant for 3DOverlays, and by setting _queryAACubeSet true here
|
||||||
|
// we can avoid incorrect evaluation for sending updates for entities with 3DOverlays children.
|
||||||
|
_queryAACubeSet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
|
Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
|
||||||
|
@ -41,6 +44,9 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
|
||||||
_isVisibleInSecondaryCamera(base3DOverlay->_isVisibleInSecondaryCamera)
|
_isVisibleInSecondaryCamera(base3DOverlay->_isVisibleInSecondaryCamera)
|
||||||
{
|
{
|
||||||
setTransform(base3DOverlay->getTransform());
|
setTransform(base3DOverlay->getTransform());
|
||||||
|
// HACK: queryAACube stuff not actually relevant for 3DOverlays, and by setting _queryAACubeSet true here
|
||||||
|
// we can avoid incorrect evaluation for sending updates for entities with 3DOverlays children.
|
||||||
|
_queryAACubeSet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& properties, bool scalesWithParent) {
|
QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& properties, bool scalesWithParent) {
|
||||||
|
@ -209,6 +215,7 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) {
|
||||||
transaction.updateItem(itemID);
|
transaction.updateItem(itemID);
|
||||||
scene->enqueueTransaction(transaction);
|
scene->enqueueTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
_queryAACubeSet = true; // HACK: just in case some SpatiallyNestable code accidentally set it false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
Base3DOverlay(const Base3DOverlay* base3DOverlay);
|
Base3DOverlay(const Base3DOverlay* base3DOverlay);
|
||||||
|
|
||||||
void setVisible(bool visible) override;
|
void setVisible(bool visible) override;
|
||||||
|
bool queryAACubeNeedsUpdate() const override { return false; } // HACK: queryAACube not relevant for Overlays
|
||||||
|
|
||||||
virtual OverlayID getOverlayID() const override { return OverlayID(getID().toString()); }
|
virtual OverlayID getOverlayID() const override { return OverlayID(getID().toString()); }
|
||||||
void setOverlayID(OverlayID overlayID) override { setID(overlayID); }
|
void setOverlayID(OverlayID overlayID) override { setID(overlayID); }
|
||||||
|
|
|
@ -394,10 +394,6 @@ void Avatar::updateAvatarEntities() {
|
||||||
properties.setEntityHostType(entity::HostType::AVATAR);
|
properties.setEntityHostType(entity::HostType::AVATAR);
|
||||||
properties.setOwningAvatarID(getID());
|
properties.setOwningAvatarID(getID());
|
||||||
|
|
||||||
// there's no entity-server to tell us we're the simulation owner, so always set the
|
|
||||||
// simulationOwner to the owningAvatarID and a high priority.
|
|
||||||
properties.setSimulationOwner(getID(), AVATAR_ENTITY_SIMULATION_PRIORITY);
|
|
||||||
|
|
||||||
if (properties.getParentID() == AVATAR_SELF_ID) {
|
if (properties.getParentID() == AVATAR_SELF_ID) {
|
||||||
properties.setParentID(getID());
|
properties.setParentID(getID());
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,6 +328,19 @@ 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);
|
||||||
|
|
||||||
|
auto traitsAckPacket = NLPacket::create(PacketType::BulkAvatarTraitsAck, sizeof(AvatarTraits::TraitMessageSequence), true);
|
||||||
|
traitsAckPacket->writePrimitive(seq);
|
||||||
|
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);
|
||||||
|
if (!avatarMixer.isNull()) {
|
||||||
|
// we have a mixer to send to, acknowledge that we received these
|
||||||
|
// traits.
|
||||||
|
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
|
||||||
|
|
|
@ -42,6 +42,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;
|
||||||
|
|
|
@ -157,7 +157,7 @@ public:
|
||||||
DEFINE_PROPERTY(PROP_CREATED, Created, created, quint64, UNKNOWN_CREATED_TIME);
|
DEFINE_PROPERTY(PROP_CREATED, Created, created, quint64, UNKNOWN_CREATED_TIME);
|
||||||
DEFINE_PROPERTY_REF(PROP_LAST_EDITED_BY, LastEditedBy, lastEditedBy, QUuid, ENTITY_ITEM_DEFAULT_LAST_EDITED_BY);
|
DEFINE_PROPERTY_REF(PROP_LAST_EDITED_BY, LastEditedBy, lastEditedBy, QUuid, ENTITY_ITEM_DEFAULT_LAST_EDITED_BY);
|
||||||
DEFINE_PROPERTY_REF_ENUM(PROP_ENTITY_HOST_TYPE, EntityHostType, entityHostType, entity::HostType, entity::HostType::DOMAIN);
|
DEFINE_PROPERTY_REF_ENUM(PROP_ENTITY_HOST_TYPE, EntityHostType, entityHostType, entity::HostType, entity::HostType::DOMAIN);
|
||||||
DEFINE_PROPERTY_REF(PROP_OWNING_AVATAR_ID, OwningAvatarID, owningAvatarID, QUuid, UNKNOWN_ENTITY_ID);
|
DEFINE_PROPERTY_REF_WITH_SETTER(PROP_OWNING_AVATAR_ID, OwningAvatarID, owningAvatarID, QUuid, UNKNOWN_ENTITY_ID);
|
||||||
DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID);
|
DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID);
|
||||||
DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, -1);
|
DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, -1);
|
||||||
DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube());
|
DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube());
|
||||||
|
@ -499,6 +499,16 @@ void EntityPropertyInfoFromScriptValue(const QScriptValue& object, EntityPropert
|
||||||
inline void EntityItemProperties::setPosition(const glm::vec3& value)
|
inline void EntityItemProperties::setPosition(const glm::vec3& value)
|
||||||
{ _position = glm::clamp(value, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); _positionChanged = true; }
|
{ _position = glm::clamp(value, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); _positionChanged = true; }
|
||||||
|
|
||||||
|
inline void EntityItemProperties::setOwningAvatarID(const QUuid& id) {
|
||||||
|
_owningAvatarID = id;
|
||||||
|
if (!_owningAvatarID.isNull()) {
|
||||||
|
// for AvatarEntities there's no entity-server to tell us we're the simulation owner,
|
||||||
|
// so always set the simulationOwner to the owningAvatarID and a high priority.
|
||||||
|
setSimulationOwner(_owningAvatarID, AVATAR_ENTITY_SIMULATION_PRIORITY);
|
||||||
|
}
|
||||||
|
_owningAvatarIDChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f);
|
QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f);
|
||||||
|
|
||||||
inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
||||||
|
|
|
@ -96,7 +96,7 @@ const uint8_t RECRUIT_SIMULATION_PRIORITY = VOLUNTEER_SIMULATION_PRIORITY + 1;
|
||||||
// When poking objects with scripts an observer will bid at SCRIPT_EDIT priority.
|
// When poking objects with scripts an observer will bid at SCRIPT_EDIT priority.
|
||||||
const uint8_t SCRIPT_GRAB_SIMULATION_PRIORITY = 128;
|
const uint8_t SCRIPT_GRAB_SIMULATION_PRIORITY = 128;
|
||||||
const uint8_t SCRIPT_POKE_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY - 1;
|
const uint8_t SCRIPT_POKE_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY - 1;
|
||||||
const uint8_t AVATAR_ENTITY_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY + 1;
|
const uint8_t AVATAR_ENTITY_SIMULATION_PRIORITY = 255;
|
||||||
|
|
||||||
// PERSONAL priority (needs a better name) is the level at which a simulation observer owns its own avatar
|
// PERSONAL priority (needs a better name) is the level at which a simulation observer owns its own avatar
|
||||||
// which really just means: things that collide with it will be bid at a priority level one lower
|
// which really just means: things that collide with it will be bid at a priority level one lower
|
||||||
|
|
|
@ -97,6 +97,9 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
return 22;
|
return 22;
|
||||||
case PacketType::EntityQueryInitialResultsComplete:
|
case PacketType::EntityQueryInitialResultsComplete:
|
||||||
return static_cast<PacketVersion>(EntityVersion::ParticleSpin);
|
return static_cast<PacketVersion>(EntityVersion::ParticleSpin);
|
||||||
|
case PacketType::BulkAvatarTraitsAck:
|
||||||
|
case PacketType::BulkAvatarTraits:
|
||||||
|
return static_cast<PacketVersion>(AvatarMixerPacketVersion::AvatarTraitsAck);
|
||||||
default:
|
default:
|
||||||
return 22;
|
return 22;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ public:
|
||||||
EntityQueryInitialResultsComplete,
|
EntityQueryInitialResultsComplete,
|
||||||
BulkAvatarTraits,
|
BulkAvatarTraits,
|
||||||
AudioSoloRequest,
|
AudioSoloRequest,
|
||||||
|
BulkAvatarTraitsAck,
|
||||||
NUM_PACKET_TYPE
|
NUM_PACKET_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -310,7 +310,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
||||||
FarGrabJointsRedux,
|
FarGrabJointsRedux,
|
||||||
JointTransScaled,
|
JointTransScaled,
|
||||||
GrabTraits,
|
GrabTraits,
|
||||||
CollisionFlag
|
CollisionFlag,
|
||||||
|
AvatarTraitsAck
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DomainConnectRequestVersion : PacketVersion {
|
enum class DomainConnectRequestVersion : PacketVersion {
|
||||||
|
|
|
@ -61,6 +61,9 @@ private:
|
||||||
Mutex2& _mutex2;
|
Mutex2& _mutex2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const microseconds SendQueue::MAXIMUM_ESTIMATED_TIMEOUT = seconds(5);
|
||||||
|
const microseconds SendQueue::MINIMUM_ESTIMATED_TIMEOUT = milliseconds(10);
|
||||||
|
|
||||||
std::unique_ptr<SendQueue> SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber,
|
std::unique_ptr<SendQueue> SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber,
|
||||||
MessageNumber currentMessageNumber, bool hasReceivedHandshakeACK) {
|
MessageNumber currentMessageNumber, bool hasReceivedHandshakeACK) {
|
||||||
Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*");
|
Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*");
|
||||||
|
@ -507,12 +510,8 @@ bool SendQueue::isInactive(bool attemptedToSendPacket) {
|
||||||
|
|
||||||
auto estimatedTimeout = std::chrono::microseconds(_estimatedTimeout);
|
auto estimatedTimeout = std::chrono::microseconds(_estimatedTimeout);
|
||||||
|
|
||||||
// cap our maximum estimated timeout to the already unreasonable 5 seconds
|
// Clamp timeout beween 10 ms and 5 s
|
||||||
const auto MAXIMUM_ESTIMATED_TIMEOUT = std::chrono::seconds(5);
|
estimatedTimeout = std::min(MAXIMUM_ESTIMATED_TIMEOUT, std::max(MINIMUM_ESTIMATED_TIMEOUT, estimatedTimeout));
|
||||||
|
|
||||||
if (estimatedTimeout > MAXIMUM_ESTIMATED_TIMEOUT) {
|
|
||||||
estimatedTimeout = MAXIMUM_ESTIMATED_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use our condition_variable_any to wait
|
// use our condition_variable_any to wait
|
||||||
auto cvStatus = _emptyCondition.wait_for(locker, estimatedTimeout);
|
auto cvStatus = _emptyCondition.wait_for(locker, estimatedTimeout);
|
||||||
|
|
|
@ -140,6 +140,9 @@ private:
|
||||||
std::condition_variable_any _emptyCondition;
|
std::condition_variable_any _emptyCondition;
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point _lastPacketSentAt;
|
std::chrono::high_resolution_clock::time_point _lastPacketSentAt;
|
||||||
|
|
||||||
|
static const std::chrono::microseconds MAXIMUM_ESTIMATED_TIMEOUT;
|
||||||
|
static const std::chrono::microseconds MINIMUM_ESTIMATED_TIMEOUT;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,6 +306,8 @@ const btCollisionShape* EntityMotionState::computeNewShape() {
|
||||||
return getShapeManager()->getShape(shapeInfo);
|
return getShapeManager()->getShape(shapeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint8_t MAX_NUM_INACTIVE_UPDATES = 20;
|
||||||
|
|
||||||
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
// NOTE: this method is only ever called when the entity simulation is locally owned
|
// NOTE: this method is only ever called when the entity simulation is locally owned
|
||||||
DETAILED_PROFILE_RANGE(simulation_physics, "CheckOutOfSync");
|
DETAILED_PROFILE_RANGE(simulation_physics, "CheckOutOfSync");
|
||||||
|
@ -315,15 +317,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
// TODO: need to be able to detect when logic dictates we *decrease* priority
|
// TODO: need to be able to detect when logic dictates we *decrease* priority
|
||||||
// WIP: print info whenever _bidPriority mismatches what is known to the entity
|
// WIP: print info whenever _bidPriority mismatches what is known to the entity
|
||||||
|
|
||||||
if (_entity->dynamicDataNeedsTransmit()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numSteps = simulationStep - _lastStep;
|
int numSteps = simulationStep - _lastStep;
|
||||||
float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||||
|
|
||||||
if (_numInactiveUpdates > 0) {
|
if (_numInactiveUpdates > 0) {
|
||||||
const uint8_t MAX_NUM_INACTIVE_UPDATES = 20;
|
|
||||||
if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES) {
|
if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES) {
|
||||||
// clear local ownership (stop sending updates) and let the server clear itself
|
// clear local ownership (stop sending updates) and let the server clear itself
|
||||||
_entity->clearSimulationOwnership();
|
_entity->clearSimulationOwnership();
|
||||||
|
@ -451,8 +448,13 @@ void EntityMotionState::updateSendVelocities() {
|
||||||
if (!_body->isKinematicObject()) {
|
if (!_body->isKinematicObject()) {
|
||||||
clearObjectVelocities();
|
clearObjectVelocities();
|
||||||
}
|
}
|
||||||
// we pretend we sent the inactive update for this object
|
if (_entity->getEntityHostType() == entity::HostType::AVATAR) {
|
||||||
_numInactiveUpdates = 1;
|
// AvatarEntities only ever need to send one update (their updates are sent over a lossless protocol)
|
||||||
|
// so we set the count to the max to prevent resends
|
||||||
|
_numInactiveUpdates = MAX_NUM_INACTIVE_UPDATES;
|
||||||
|
} else {
|
||||||
|
++_numInactiveUpdates;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
glm::vec3 gravity = _entity->getGravity();
|
glm::vec3 gravity = _entity->getGravity();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue