mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 17:41:12 +02:00
Merge pull request #10255 from ZappoMan/retrySkeletonURL
Fix two cases for avatars stuck in T-Pose
This commit is contained in:
commit
df7cb09fe4
22 changed files with 145 additions and 137 deletions
|
@ -544,7 +544,7 @@ void Agent::setIsAvatar(bool isAvatar) {
|
||||||
connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket);
|
connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket);
|
||||||
|
|
||||||
// start the timers
|
// start the timers
|
||||||
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
|
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); // FIXME - we shouldn't really need to constantly send identity packets
|
||||||
|
|
||||||
// tell the avatarAudioTimer to start ticking
|
// tell the avatarAudioTimer to start ticking
|
||||||
emit startAvatarAudioTimer();
|
emit startAvatarAudioTimer();
|
||||||
|
|
|
@ -71,15 +71,10 @@ AvatarMixer::~AvatarMixer() {
|
||||||
|
|
||||||
void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
||||||
QByteArray individualData = nodeData->getAvatar().identityByteArray();
|
QByteArray individualData = nodeData->getAvatar().identityByteArray();
|
||||||
|
|
||||||
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
|
|
||||||
|
|
||||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122());
|
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122());
|
||||||
|
auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
||||||
identityPacket->write(individualData);
|
identityPackets->write(individualData);
|
||||||
|
DependencyManager::get<NodeList>()->sendPacketList(std::move(identityPackets), *destinationNode);
|
||||||
DependencyManager::get<NodeList>()->sendPacket(std::move(identityPacket), *destinationNode);
|
|
||||||
|
|
||||||
++_sumIdentityPackets;
|
++_sumIdentityPackets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -263,16 +263,8 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
// make sure we haven't already sent this data from this sender to this receiver
|
// make sure we haven't already sent this data from this sender to this receiver
|
||||||
// or that somehow we haven't sent
|
// or that somehow we haven't sent
|
||||||
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
||||||
// don't ignore this avatar if we haven't sent any update for a long while
|
++numAvatarsHeldBack;
|
||||||
// in an effort to prevent other interfaces from deleting a stale avatar instance
|
shouldIgnore = true;
|
||||||
uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(avatarNode->getUUID());
|
|
||||||
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
|
||||||
const uint64_t AVATAR_UPDATE_STALE = AVATAR_UPDATE_TIMEOUT - USECS_PER_SECOND;
|
|
||||||
if (lastBroadcastTime > otherNodeData->getIdentityChangeTimestamp() &&
|
|
||||||
lastBroadcastTime + AVATAR_UPDATE_STALE > startIgnoreCalculation) {
|
|
||||||
++numAvatarsHeldBack;
|
|
||||||
shouldIgnore = true;
|
|
||||||
}
|
|
||||||
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
|
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
|
||||||
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
|
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
|
||||||
++numAvatarsWithSkippedFrames;
|
++numAvatarsWithSkippedFrames;
|
||||||
|
@ -285,7 +277,7 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
int avatarRank = 0;
|
int avatarRank = 0;
|
||||||
|
|
||||||
// this is overly conservative, because it includes some avatars we might not consider
|
// this is overly conservative, because it includes some avatars we might not consider
|
||||||
int remainingAvatars = (int)sortedAvatars.size();
|
int remainingAvatars = (int)sortedAvatars.size();
|
||||||
|
|
||||||
while (!sortedAvatars.empty()) {
|
while (!sortedAvatars.empty()) {
|
||||||
AvatarPriority sortData = sortedAvatars.top();
|
AvatarPriority sortData = sortedAvatars.top();
|
||||||
|
|
|
@ -5216,11 +5216,7 @@ void Application::resettingDomain() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::nodeAdded(SharedNodePointer node) const {
|
void Application::nodeAdded(SharedNodePointer node) const {
|
||||||
if (node->getType() == NodeType::AvatarMixer) {
|
// nothing to do here
|
||||||
// new avatar mixer, send off our identity packet right away
|
|
||||||
getMyAvatar()->sendIdentityPacket();
|
|
||||||
getMyAvatar()->resetLastSent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::nodeActivated(SharedNodePointer node) {
|
void Application::nodeActivated(SharedNodePointer node) {
|
||||||
|
@ -5256,6 +5252,13 @@ void Application::nodeActivated(SharedNodePointer node) {
|
||||||
if (node->getType() == NodeType::AudioMixer) {
|
if (node->getType() == NodeType::AudioMixer) {
|
||||||
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->getType() == NodeType::AvatarMixer) {
|
||||||
|
// new avatar mixer, send off our identity packet right away
|
||||||
|
getMyAvatar()->markIdentityDataChanged();
|
||||||
|
getMyAvatar()->sendIdentityPacket();
|
||||||
|
getMyAvatar()->resetLastSent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::nodeKilled(SharedNodePointer node) {
|
void Application::nodeKilled(SharedNodePointer node) {
|
||||||
|
|
|
@ -115,8 +115,6 @@ Avatar::Avatar(QThread* thread, RigPointer rig) :
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar::~Avatar() {
|
Avatar::~Avatar() {
|
||||||
assert(isDead()); // mark dead before calling the dtor
|
|
||||||
|
|
||||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||||
if (entityTree) {
|
if (entityTree) {
|
||||||
|
@ -510,12 +508,13 @@ static TextRenderer3D* textRenderer(TextRendererType type) {
|
||||||
void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||||
auto avatarPayload = new render::Payload<AvatarData>(self);
|
auto avatarPayload = new render::Payload<AvatarData>(self);
|
||||||
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
|
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
|
||||||
_renderItemID = scene->allocateID();
|
if (_skeletonModel->addToScene(scene, transaction)) {
|
||||||
transaction.resetItem(_renderItemID, avatarPayloadPointer);
|
_renderItemID = scene->allocateID();
|
||||||
_skeletonModel->addToScene(scene, transaction);
|
transaction.resetItem(_renderItemID, avatarPayloadPointer);
|
||||||
|
|
||||||
for (auto& attachmentModel : _attachmentModels) {
|
for (auto& attachmentModel : _attachmentModels) {
|
||||||
attachmentModel->addToScene(scene, transaction);
|
attachmentModel->addToScene(scene, transaction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,11 +1122,20 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
|
|
||||||
void Avatar::setModelURLFinished(bool success) {
|
void Avatar::setModelURLFinished(bool success) {
|
||||||
if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) {
|
if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) {
|
||||||
qCWarning(interfaceapp) << "Using default after failing to load Avatar model: " << _skeletonModelURL;
|
const int MAX_SKELETON_DOWNLOAD_ATTEMPTS = 4; // NOTE: we don't want to be as generous as ResourceCache is, we only want 4 attempts
|
||||||
// call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that
|
if (_skeletonModel->getResourceDownloadAttemptsRemaining() <= 0 ||
|
||||||
// we don't redo this every time we receive an identity packet from the avatar with the bad url.
|
_skeletonModel->getResourceDownloadAttempts() > MAX_SKELETON_DOWNLOAD_ATTEMPTS) {
|
||||||
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL",
|
qCWarning(interfaceapp) << "Using default after failing to load Avatar model: " << _skeletonModelURL
|
||||||
Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl()));
|
<< "after" << _skeletonModel->getResourceDownloadAttempts() << "attempts.";
|
||||||
|
// call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that
|
||||||
|
// we don't redo this every time we receive an identity packet from the avatar with the bad url.
|
||||||
|
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl()));
|
||||||
|
} else {
|
||||||
|
qCWarning(interfaceapp) << "Avatar model: " << _skeletonModelURL
|
||||||
|
<< "failed to load... attempts:" << _skeletonModel->getResourceDownloadAttempts()
|
||||||
|
<< "out of:" << MAX_SKELETON_DOWNLOAD_ATTEMPTS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,10 +213,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
avatar->animateScaleChanges(deltaTime);
|
avatar->animateScaleChanges(deltaTime);
|
||||||
if (avatar->shouldDie()) {
|
|
||||||
avatar->die();
|
|
||||||
removeAvatar(avatar->getID());
|
|
||||||
}
|
|
||||||
|
|
||||||
const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY;
|
const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY;
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
|
@ -330,44 +326,12 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() {
|
||||||
return std::make_shared<Avatar>(qApp->thread(), std::make_shared<Rig>());
|
return std::make_shared<Avatar>(qApp->thread(), std::make_shared<Rig>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarManager::processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
|
||||||
PerformanceTimer perfTimer("receiveAvatar");
|
|
||||||
// enumerate over all of the avatars in this packet
|
|
||||||
// only add them if mixerWeakPointer points to something (meaning that mixer is still around)
|
|
||||||
while (message->getBytesLeftToRead()) {
|
|
||||||
AvatarSharedPointer avatarData = parseAvatarData(message, sendingNode);
|
|
||||||
if (avatarData) {
|
|
||||||
auto avatar = std::static_pointer_cast<Avatar>(avatarData);
|
|
||||||
if (avatar->isInScene()) {
|
|
||||||
if (!_shouldRender) {
|
|
||||||
// rare transition so we process the transaction immediately
|
|
||||||
const render::ScenePointer& scene = qApp->getMain3DScene();
|
|
||||||
render::Transaction transaction;
|
|
||||||
avatar->removeFromScene(avatar, scene, transaction);
|
|
||||||
if (scene) {
|
|
||||||
scene->enqueueTransaction(transaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (_shouldRender) {
|
|
||||||
// very rare transition so we process the transaction immediately
|
|
||||||
const render::ScenePointer& scene = qApp->getMain3DScene();
|
|
||||||
render::Transaction transaction;
|
|
||||||
avatar->addToScene(avatar, scene, transaction);
|
|
||||||
if (scene) {
|
|
||||||
scene->enqueueTransaction(transaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
||||||
AvatarHashMap::handleRemovedAvatar(removedAvatar, removalReason);
|
AvatarHashMap::handleRemovedAvatar(removedAvatar, removalReason);
|
||||||
|
|
||||||
// removedAvatar is a shared pointer to an AvatarData but we need to get to the derived Avatar
|
// removedAvatar is a shared pointer to an AvatarData but we need to get to the derived Avatar
|
||||||
// class in this context so we can call methods that don't exist at the base class.
|
// class in this context so we can call methods that don't exist at the base class.
|
||||||
Avatar* avatar = static_cast<Avatar*>(removedAvatar.get());
|
auto avatar = std::static_pointer_cast<Avatar>(removedAvatar);
|
||||||
avatar->die();
|
|
||||||
|
|
||||||
AvatarMotionState* motionState = avatar->getMotionState();
|
AvatarMotionState* motionState = avatar->getMotionState();
|
||||||
if (motionState) {
|
if (motionState) {
|
||||||
|
@ -403,14 +367,11 @@ void AvatarManager::clearOtherAvatars() {
|
||||||
if (avatar->isInScene()) {
|
if (avatar->isInScene()) {
|
||||||
avatar->removeFromScene(avatar, scene, transaction);
|
avatar->removeFromScene(avatar, scene, transaction);
|
||||||
}
|
}
|
||||||
AvatarMotionState* motionState = avatar->getMotionState();
|
handleRemovedAvatar(avatar);
|
||||||
if (motionState) {
|
avatarIterator = _avatarHash.erase(avatarIterator);
|
||||||
_motionStatesThatMightUpdate.remove(motionState);
|
} else {
|
||||||
_motionStatesToAddToPhysics.remove(motionState);
|
++avatarIterator;
|
||||||
_motionStatesToRemoveFromPhysics.push_back(motionState);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
++avatarIterator;
|
|
||||||
}
|
}
|
||||||
scene->enqueueTransaction(transaction);
|
scene->enqueueTransaction(transaction);
|
||||||
_myAvatar->clearLookAtTargetAvatar();
|
_myAvatar->clearLookAtTargetAvatar();
|
||||||
|
|
|
@ -98,9 +98,6 @@ public slots:
|
||||||
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
|
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
|
||||||
void updateAvatarRenderStatus(bool shouldRenderAvatars);
|
void updateAvatarRenderStatus(bool shouldRenderAvatars);
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit AvatarManager(QObject* parent = 0);
|
explicit AvatarManager(QObject* parent = 0);
|
||||||
explicit AvatarManager(const AvatarManager& other);
|
explicit AvatarManager(const AvatarManager& other);
|
||||||
|
|
|
@ -412,9 +412,7 @@ void MyAvatar::update(float deltaTime) {
|
||||||
Q_ARG(glm::vec3, (getPosition() - halfBoundingBoxDimensions)),
|
Q_ARG(glm::vec3, (getPosition() - halfBoundingBoxDimensions)),
|
||||||
Q_ARG(glm::vec3, (halfBoundingBoxDimensions*2.0f)));
|
Q_ARG(glm::vec3, (halfBoundingBoxDimensions*2.0f)));
|
||||||
|
|
||||||
uint64_t now = usecTimestampNow();
|
if (getIdentityDataChanged()) {
|
||||||
if (now > _identityPacketExpiry || _avatarEntityDataLocallyEdited) {
|
|
||||||
_identityPacketExpiry = now + AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS;
|
|
||||||
sendIdentityPacket();
|
sendIdentityPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,7 +1256,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
|
||||||
setSkeletonModelURL(fullAvatarURL);
|
setSkeletonModelURL(fullAvatarURL);
|
||||||
UserActivityLogger::getInstance().changedModel("skeleton", urlString);
|
UserActivityLogger::getInstance().changedModel("skeleton", urlString);
|
||||||
}
|
}
|
||||||
_identityPacketExpiry = 0; // triggers an identity packet next update()
|
markIdentityDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||||
|
|
|
@ -701,8 +701,6 @@ private:
|
||||||
std::mutex _holdActionsMutex;
|
std::mutex _holdActionsMutex;
|
||||||
std::vector<AvatarActionHold*> _holdActions;
|
std::vector<AvatarActionHold*> _holdActions;
|
||||||
|
|
||||||
uint64_t _identityPacketExpiry { 0 };
|
|
||||||
|
|
||||||
float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f };
|
float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f };
|
||||||
float AUDIO_ENERGY_CONSTANT { 0.000001f };
|
float AUDIO_ENERGY_CONSTANT { 0.000001f };
|
||||||
float MAX_AVATAR_MOVEMENT_PER_FRAME { 30.0f };
|
float MAX_AVATAR_MOVEMENT_PER_FRAME { 30.0f };
|
||||||
|
|
|
@ -79,6 +79,25 @@ int main(int argc, const char* argv[]) {
|
||||||
instanceMightBeRunning = false;
|
instanceMightBeRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QCommandLineParser parser;
|
||||||
|
QCommandLineOption checkMinSpecOption("checkMinSpec", "Check if machine meets minimum specifications");
|
||||||
|
QCommandLineOption runServerOption("runServer", "Whether to run the server");
|
||||||
|
QCommandLineOption serverContentPathOption("serverContentPath", "Where to find server content", "serverContentPath");
|
||||||
|
QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run");
|
||||||
|
parser.addOption(checkMinSpecOption);
|
||||||
|
parser.addOption(runServerOption);
|
||||||
|
parser.addOption(serverContentPathOption);
|
||||||
|
parser.addOption(allowMultipleInstancesOption);
|
||||||
|
parser.parse(arguments);
|
||||||
|
bool runServer = parser.isSet(runServerOption);
|
||||||
|
bool serverContentPathOptionIsSet = parser.isSet(serverContentPathOption);
|
||||||
|
QString serverContentPathOptionValue = serverContentPathOptionIsSet ? parser.value(serverContentPathOption) : QString();
|
||||||
|
bool allowMultipleInstances = parser.isSet(allowMultipleInstancesOption);
|
||||||
|
|
||||||
|
if (allowMultipleInstances) {
|
||||||
|
instanceMightBeRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (instanceMightBeRunning) {
|
if (instanceMightBeRunning) {
|
||||||
// Try to connect and send message to existing interface instance
|
// Try to connect and send message to existing interface instance
|
||||||
QLocalSocket socket;
|
QLocalSocket socket;
|
||||||
|
@ -137,18 +156,6 @@ int main(int argc, const char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QCommandLineParser parser;
|
|
||||||
QCommandLineOption checkMinSpecOption("checkMinSpec", "Check if machine meets minimum specifications");
|
|
||||||
QCommandLineOption runServerOption("runServer", "Whether to run the server");
|
|
||||||
QCommandLineOption serverContentPathOption("serverContentPath", "Where to find server content", "serverContentPath");
|
|
||||||
parser.addOption(checkMinSpecOption);
|
|
||||||
parser.addOption(runServerOption);
|
|
||||||
parser.addOption(serverContentPathOption);
|
|
||||||
parser.parse(arguments);
|
|
||||||
bool runServer = parser.isSet(runServerOption);
|
|
||||||
bool serverContentPathOptionIsSet = parser.isSet(serverContentPathOption);
|
|
||||||
QString serverContentPathOptionValue = serverContentPathOptionIsSet ? parser.value(serverContentPathOption) : QString();
|
|
||||||
|
|
||||||
QElapsedTimer startupTime;
|
QElapsedTimer startupTime;
|
||||||
startupTime.start();
|
startupTime.start();
|
||||||
|
|
||||||
|
|
|
@ -1473,7 +1473,22 @@ QStringList AvatarData::getJointNames() const {
|
||||||
void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) {
|
void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) {
|
||||||
QDataStream packetStream(data);
|
QDataStream packetStream(data);
|
||||||
|
|
||||||
packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.sessionDisplayName >> identityOut.avatarEntityData;
|
packetStream >> identityOut.uuid
|
||||||
|
>> identityOut.skeletonModelURL
|
||||||
|
>> identityOut.attachmentData
|
||||||
|
>> identityOut.displayName
|
||||||
|
>> identityOut.sessionDisplayName
|
||||||
|
>> identityOut.avatarEntityData
|
||||||
|
>> identityOut.updatedAt;
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
qCDebug(avatars) << __FUNCTION__
|
||||||
|
<< "identityOut.uuid:" << identityOut.uuid
|
||||||
|
<< "identityOut.skeletonModelURL:" << identityOut.skeletonModelURL
|
||||||
|
<< "identityOut.displayName:" << identityOut.displayName
|
||||||
|
<< "identityOut.sessionDisplayName:" << identityOut.sessionDisplayName;
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QUrl emptyURL("");
|
static const QUrl emptyURL("");
|
||||||
|
@ -1484,6 +1499,12 @@ QUrl AvatarData::cannonicalSkeletonModelURL(const QUrl& emptyURL) const {
|
||||||
|
|
||||||
void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityChanged, bool& displayNameChanged) {
|
void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityChanged, bool& displayNameChanged) {
|
||||||
|
|
||||||
|
if (identity.updatedAt < _identityUpdatedAt) {
|
||||||
|
qCDebug(avatars) << "Ignoring late identity packet for avatar " << getSessionUUID()
|
||||||
|
<< "identity.updatedAt:" << identity.updatedAt << "_identityUpdatedAt:" << _identityUpdatedAt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) {
|
if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) {
|
||||||
setSkeletonModelURL(identity.skeletonModelURL);
|
setSkeletonModelURL(identity.skeletonModelURL);
|
||||||
identityChanged = true;
|
identityChanged = true;
|
||||||
|
@ -1513,24 +1534,35 @@ void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityC
|
||||||
setAvatarEntityData(identity.avatarEntityData);
|
setAvatarEntityData(identity.avatarEntityData);
|
||||||
identityChanged = true;
|
identityChanged = true;
|
||||||
}
|
}
|
||||||
// flag this avatar as non-stale by updating _averageBytesReceived
|
|
||||||
const int BOGUS_NUM_BYTES = 1;
|
// use the timestamp from this identity, since we want to honor the updated times in "server clock"
|
||||||
_averageBytesReceived.updateAverage(BOGUS_NUM_BYTES);
|
// this will overwrite any changes we made locally to this AvatarData's _identityUpdatedAt
|
||||||
|
_identityUpdatedAt = identity.updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray AvatarData::identityByteArray() const {
|
QByteArray AvatarData::identityByteArray() const {
|
||||||
QByteArray identityData;
|
QByteArray identityData;
|
||||||
QDataStream identityStream(&identityData, QIODevice::Append);
|
QDataStream identityStream(&identityData, QIODevice::Append);
|
||||||
const QUrl& urlToSend = cannonicalSkeletonModelURL(emptyURL);
|
const QUrl& urlToSend = cannonicalSkeletonModelURL(emptyURL); // depends on _skeletonModelURL
|
||||||
|
|
||||||
_avatarEntitiesLock.withReadLock([&] {
|
_avatarEntitiesLock.withReadLock([&] {
|
||||||
identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << getSessionDisplayNameForTransport() << _avatarEntityData;
|
identityStream << getSessionUUID()
|
||||||
|
<< urlToSend
|
||||||
|
<< _attachmentData
|
||||||
|
<< _displayName
|
||||||
|
<< getSessionDisplayNameForTransport() // depends on _sessionDisplayName
|
||||||
|
<< _avatarEntityData
|
||||||
|
<< _identityUpdatedAt;
|
||||||
});
|
});
|
||||||
|
|
||||||
return identityData;
|
return identityData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
|
if (skeletonModelURL.isEmpty()) {
|
||||||
|
qCDebug(avatars) << __FUNCTION__ << "caller called with empty URL.";
|
||||||
|
}
|
||||||
|
|
||||||
const QUrl& expanded = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL;
|
const QUrl& expanded = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL;
|
||||||
if (expanded == _skeletonModelURL) {
|
if (expanded == _skeletonModelURL) {
|
||||||
return;
|
return;
|
||||||
|
@ -1539,6 +1571,7 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
qCDebug(avatars) << "Changing skeleton model for avatar" << getSessionUUID() << "to" << _skeletonModelURL.toString();
|
qCDebug(avatars) << "Changing skeleton model for avatar" << getSessionUUID() << "to" << _skeletonModelURL.toString();
|
||||||
|
|
||||||
updateJointMappings();
|
updateJointMappings();
|
||||||
|
markIdentityDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::setDisplayName(const QString& displayName) {
|
void AvatarData::setDisplayName(const QString& displayName) {
|
||||||
|
@ -1548,6 +1581,7 @@ void AvatarData::setDisplayName(const QString& displayName) {
|
||||||
sendIdentityPacket();
|
sendIdentityPacket();
|
||||||
|
|
||||||
qCDebug(avatars) << "Changing display name for avatar to" << displayName;
|
qCDebug(avatars) << "Changing display name for avatar to" << displayName;
|
||||||
|
markIdentityDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<AttachmentData> AvatarData::getAttachmentData() const {
|
QVector<AttachmentData> AvatarData::getAttachmentData() const {
|
||||||
|
@ -1566,6 +1600,7 @@ void AvatarData::setAttachmentData(const QVector<AttachmentData>& attachmentData
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_attachmentData = attachmentData;
|
_attachmentData = attachmentData;
|
||||||
|
markIdentityDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::attach(const QString& modelURL, const QString& jointName,
|
void AvatarData::attach(const QString& modelURL, const QString& jointName,
|
||||||
|
@ -1695,7 +1730,6 @@ void AvatarData::sendAvatarDataPacket() {
|
||||||
|
|
||||||
void AvatarData::sendIdentityPacket() {
|
void AvatarData::sendIdentityPacket() {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
QByteArray identityData = identityByteArray();
|
QByteArray identityData = identityByteArray();
|
||||||
|
|
||||||
auto packetList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
auto packetList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
||||||
|
@ -1709,6 +1743,7 @@ void AvatarData::sendIdentityPacket() {
|
||||||
});
|
});
|
||||||
|
|
||||||
_avatarEntityDataLocallyEdited = false;
|
_avatarEntityDataLocallyEdited = false;
|
||||||
|
_identityDataChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::updateJointMappings() {
|
void AvatarData::updateJointMappings() {
|
||||||
|
@ -2245,10 +2280,12 @@ void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& ent
|
||||||
if (_avatarEntityData.size() < MAX_NUM_AVATAR_ENTITIES) {
|
if (_avatarEntityData.size() < MAX_NUM_AVATAR_ENTITIES) {
|
||||||
_avatarEntityData.insert(entityID, entityData);
|
_avatarEntityData.insert(entityID, entityData);
|
||||||
_avatarEntityDataLocallyEdited = true;
|
_avatarEntityDataLocallyEdited = true;
|
||||||
|
markIdentityDataChanged();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
itr.value() = entityData;
|
itr.value() = entityData;
|
||||||
_avatarEntityDataLocallyEdited = true;
|
_avatarEntityDataLocallyEdited = true;
|
||||||
|
markIdentityDataChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2262,6 +2299,7 @@ void AvatarData::clearAvatarEntity(const QUuid& entityID) {
|
||||||
_avatarEntitiesLock.withWriteLock([&] {
|
_avatarEntitiesLock.withWriteLock([&] {
|
||||||
_avatarEntityData.remove(entityID);
|
_avatarEntityData.remove(entityID);
|
||||||
_avatarEntityDataLocallyEdited = true;
|
_avatarEntityDataLocallyEdited = true;
|
||||||
|
markIdentityDataChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,9 +110,7 @@ const char LEFT_HAND_POINTING_FLAG = 1;
|
||||||
const char RIGHT_HAND_POINTING_FLAG = 2;
|
const char RIGHT_HAND_POINTING_FLAG = 2;
|
||||||
const char IS_FINGER_POINTING_FLAG = 4;
|
const char IS_FINGER_POINTING_FLAG = 4;
|
||||||
|
|
||||||
const qint64 AVATAR_UPDATE_TIMEOUT = 5 * USECS_PER_SECOND;
|
// AvatarData state flags - we store the details about the packet encoding in the first byte,
|
||||||
|
|
||||||
// AvatarData state flags - we store the details about the packet encoding in the first byte,
|
|
||||||
// before the "header" structure
|
// before the "header" structure
|
||||||
const char AVATARDATA_FLAGS_MINIMUM = 0;
|
const char AVATARDATA_FLAGS_MINIMUM = 0;
|
||||||
|
|
||||||
|
@ -531,6 +529,7 @@ public:
|
||||||
QString displayName;
|
QString displayName;
|
||||||
QString sessionDisplayName;
|
QString sessionDisplayName;
|
||||||
AvatarEntityMap avatarEntityData;
|
AvatarEntityMap avatarEntityData;
|
||||||
|
quint64 updatedAt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut);
|
static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut);
|
||||||
|
@ -547,7 +546,10 @@ public:
|
||||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||||
|
|
||||||
virtual void setDisplayName(const QString& displayName);
|
virtual void setDisplayName(const QString& displayName);
|
||||||
virtual void setSessionDisplayName(const QString& sessionDisplayName) { _sessionDisplayName = sessionDisplayName; };
|
virtual void setSessionDisplayName(const QString& sessionDisplayName) {
|
||||||
|
_sessionDisplayName = sessionDisplayName;
|
||||||
|
markIdentityDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
Q_INVOKABLE QVector<AttachmentData> getAttachmentData() const;
|
Q_INVOKABLE QVector<AttachmentData> getAttachmentData() const;
|
||||||
Q_INVOKABLE virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
|
Q_INVOKABLE virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
|
||||||
|
@ -565,7 +567,6 @@ public:
|
||||||
|
|
||||||
void setOwningAvatarMixer(const QWeakPointer<Node>& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
|
void setOwningAvatarMixer(const QWeakPointer<Node>& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
|
||||||
|
|
||||||
int getUsecsSinceLastUpdate() const { return _averageBytesReceived.getUsecsSinceLastEvent(); }
|
|
||||||
int getAverageBytesReceivedPerSecond() const;
|
int getAverageBytesReceivedPerSecond() const;
|
||||||
int getReceiveRate() const;
|
int getReceiveRate() const;
|
||||||
|
|
||||||
|
@ -601,9 +602,6 @@ public:
|
||||||
return _lastSentJointData;
|
return _lastSentJointData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_UPDATE_TIMEOUT; }
|
|
||||||
|
|
||||||
static const float OUT_OF_VIEW_PENALTY;
|
static const float OUT_OF_VIEW_PENALTY;
|
||||||
|
|
||||||
static void sortAvatars(
|
static void sortAvatars(
|
||||||
|
@ -620,11 +618,15 @@ public:
|
||||||
static float _avatarSortCoefficientCenter;
|
static float _avatarSortCoefficientCenter;
|
||||||
static float _avatarSortCoefficientAge;
|
static float _avatarSortCoefficientAge;
|
||||||
|
|
||||||
|
bool getIdentityDataChanged() const { return _identityDataChanged; } // has the identity data changed since the last time sendIdentityPacket() was called
|
||||||
|
void markIdentityDataChanged() {
|
||||||
|
_identityDataChanged = true;
|
||||||
|
_identityUpdatedAt = usecTimestampNow();
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void displayNameChanged();
|
void displayNameChanged();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void sendAvatarDataPacket();
|
void sendAvatarDataPacket();
|
||||||
void sendIdentityPacket();
|
void sendIdentityPacket();
|
||||||
|
@ -779,6 +781,9 @@ protected:
|
||||||
quint64 _audioLoudnessChanged { 0 };
|
quint64 _audioLoudnessChanged { 0 };
|
||||||
float _audioAverageLoudness { 0.0f };
|
float _audioAverageLoudness { 0.0f };
|
||||||
|
|
||||||
|
bool _identityDataChanged { false };
|
||||||
|
quint64 _identityUpdatedAt { 0 };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
||||||
static QUrl _defaultFullAvatarModelUrl;
|
static QUrl _defaultFullAvatarModelUrl;
|
||||||
|
|
|
@ -57,7 +57,7 @@ public slots:
|
||||||
protected slots:
|
protected slots:
|
||||||
void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID);
|
void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID);
|
||||||
|
|
||||||
virtual void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
||||||
void processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
void processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
||||||
void processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
void processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
||||||
void processExitingSpaceBubble(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
void processExitingSpaceBubble(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
||||||
|
|
|
@ -112,6 +112,8 @@ public:
|
||||||
void setResource(GeometryResource::Pointer resource);
|
void setResource(GeometryResource::Pointer resource);
|
||||||
|
|
||||||
QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); }
|
QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); }
|
||||||
|
int getResourceDownloadAttempts() { return _resource ? _resource->getDownloadAttempts() : 0; }
|
||||||
|
int getResourceDownloadAttemptsRemaining() { return _resource ? _resource->getDownloadAttemptsRemaining() : 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startWatching();
|
void startWatching();
|
||||||
|
|
|
@ -56,7 +56,6 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
|
||||||
NetworkPeer(uuid, publicSocket, localSocket, parent),
|
NetworkPeer(uuid, publicSocket, localSocket, parent),
|
||||||
_type(type),
|
_type(type),
|
||||||
_connectionSecret(connectionSecret),
|
_connectionSecret(connectionSecret),
|
||||||
_isAlive(true),
|
|
||||||
_pingMs(-1), // "Uninitialized"
|
_pingMs(-1), // "Uninitialized"
|
||||||
_clockSkewUsec(0),
|
_clockSkewUsec(0),
|
||||||
_mutex(),
|
_mutex(),
|
||||||
|
|
|
@ -54,9 +54,6 @@ public:
|
||||||
NodeData* getLinkedData() const { return _linkedData.get(); }
|
NodeData* getLinkedData() const { return _linkedData.get(); }
|
||||||
void setLinkedData(std::unique_ptr<NodeData> linkedData) { _linkedData = std::move(linkedData); }
|
void setLinkedData(std::unique_ptr<NodeData> linkedData) { _linkedData = std::move(linkedData); }
|
||||||
|
|
||||||
bool isAlive() const { return _isAlive; }
|
|
||||||
void setAlive(bool isAlive) { _isAlive = isAlive; }
|
|
||||||
|
|
||||||
int getPingMs() const { return _pingMs; }
|
int getPingMs() const { return _pingMs; }
|
||||||
void setPingMs(int pingMs) { _pingMs = pingMs; }
|
void setPingMs(int pingMs) { _pingMs = pingMs; }
|
||||||
|
|
||||||
|
@ -92,7 +89,6 @@ private:
|
||||||
|
|
||||||
QUuid _connectionSecret;
|
QUuid _connectionSecret;
|
||||||
std::unique_ptr<NodeData> _linkedData;
|
std::unique_ptr<NodeData> _linkedData;
|
||||||
bool _isAlive;
|
|
||||||
int _pingMs;
|
int _pingMs;
|
||||||
qint64 _clockSkewUsec;
|
qint64 _clockSkewUsec;
|
||||||
QMutex _mutex;
|
QMutex _mutex;
|
||||||
|
|
|
@ -26,8 +26,7 @@ ReceivedMessage::ReceivedMessage(const NLPacketList& packetList)
|
||||||
_sourceID(packetList.getSourceID()),
|
_sourceID(packetList.getSourceID()),
|
||||||
_packetType(packetList.getType()),
|
_packetType(packetList.getType()),
|
||||||
_packetVersion(packetList.getVersion()),
|
_packetVersion(packetList.getVersion()),
|
||||||
_senderSockAddr(packetList.getSenderSockAddr()),
|
_senderSockAddr(packetList.getSenderSockAddr())
|
||||||
_isComplete(true)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -627,8 +627,6 @@ void Resource::init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int MAX_ATTEMPTS = 8;
|
|
||||||
|
|
||||||
void Resource::attemptRequest() {
|
void Resource::attemptRequest() {
|
||||||
_startedLoading = true;
|
_startedLoading = true;
|
||||||
|
|
||||||
|
@ -746,14 +744,17 @@ bool Resource::handleFailedRequest(ResourceRequest::Result result) {
|
||||||
// Fall through to other cases
|
// Fall through to other cases
|
||||||
}
|
}
|
||||||
case ResourceRequest::Result::ServerUnavailable: {
|
case ResourceRequest::Result::ServerUnavailable: {
|
||||||
|
_attempts++;
|
||||||
|
_attemptsRemaining--;
|
||||||
|
|
||||||
|
qCDebug(networking) << "Retriable error while loading" << _url << "attempt:" << _attempts << "attemptsRemaining:" << _attemptsRemaining;
|
||||||
|
|
||||||
// retry with increasing delays
|
// retry with increasing delays
|
||||||
const int BASE_DELAY_MS = 1000;
|
const int BASE_DELAY_MS = 1000;
|
||||||
if (_attempts++ < MAX_ATTEMPTS) {
|
if (_attempts < MAX_ATTEMPTS) {
|
||||||
auto waitTime = BASE_DELAY_MS * (int)pow(2.0, _attempts);
|
auto waitTime = BASE_DELAY_MS * (int)pow(2.0, _attempts);
|
||||||
|
|
||||||
qCDebug(networking).noquote() << "Server unavailable for" << _url << "- may retry in" << waitTime << "ms"
|
qCDebug(networking).noquote() << "Server unavailable for" << _url << "- may retry in" << waitTime << "ms"
|
||||||
<< "if resource is still needed";
|
<< "if resource is still needed";
|
||||||
|
|
||||||
QTimer::singleShot(waitTime, this, &Resource::attemptRequest);
|
QTimer::singleShot(waitTime, this, &Resource::attemptRequest);
|
||||||
willRetry = true;
|
willRetry = true;
|
||||||
break;
|
break;
|
||||||
|
@ -761,9 +762,10 @@ bool Resource::handleFailedRequest(ResourceRequest::Result result) {
|
||||||
// fall through to final failure
|
// fall through to final failure
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
qCDebug(networking) << "Error loading " << _url;
|
_attemptsRemaining = 0;
|
||||||
|
qCDebug(networking) << "Error loading " << _url << "attempt:" << _attempts << "attemptsRemaining:" << _attemptsRemaining;
|
||||||
auto error = (result == ResourceRequest::Timeout) ? QNetworkReply::TimeoutError
|
auto error = (result == ResourceRequest::Timeout) ? QNetworkReply::TimeoutError
|
||||||
: QNetworkReply::UnknownNetworkError;
|
: QNetworkReply::UnknownNetworkError;
|
||||||
emit failed(error);
|
emit failed(error);
|
||||||
willRetry = false;
|
willRetry = false;
|
||||||
finishedLoading(false);
|
finishedLoading(false);
|
||||||
|
|
|
@ -395,6 +395,9 @@ public:
|
||||||
|
|
||||||
const QUrl& getURL() const { return _url; }
|
const QUrl& getURL() const { return _url; }
|
||||||
|
|
||||||
|
unsigned int getDownloadAttempts() { return _attempts; }
|
||||||
|
unsigned int getDownloadAttemptsRemaining() { return _attemptsRemaining; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/// Fired when the resource begins downloading.
|
/// Fired when the resource begins downloading.
|
||||||
void loading();
|
void loading();
|
||||||
|
@ -483,7 +486,9 @@ private:
|
||||||
|
|
||||||
int _lruKey{ 0 };
|
int _lruKey{ 0 };
|
||||||
QTimer* _replyTimer{ nullptr };
|
QTimer* _replyTimer{ nullptr };
|
||||||
int _attempts{ 0 };
|
unsigned int _attempts{ 0 };
|
||||||
|
static const int MAX_ATTEMPTS = 8;
|
||||||
|
unsigned int _attemptsRemaining { MAX_ATTEMPTS };
|
||||||
bool _isInScript{ false };
|
bool _isInScript{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::AvatarData:
|
case PacketType::AvatarData:
|
||||||
case PacketType::BulkAvatarData:
|
case PacketType::BulkAvatarData:
|
||||||
case PacketType::KillAvatar:
|
case PacketType::KillAvatar:
|
||||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::StickAndBallDefaultAvatar);
|
return static_cast<PacketVersion>(AvatarMixerPacketVersion::IdentityPacketsIncludeUpdateTime);
|
||||||
case PacketType::MessagesData:
|
case PacketType::MessagesData:
|
||||||
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
||||||
case PacketType::ICEServerHeartbeat:
|
case PacketType::ICEServerHeartbeat:
|
||||||
|
|
|
@ -231,7 +231,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
||||||
ImmediateSessionDisplayNameUpdates,
|
ImmediateSessionDisplayNameUpdates,
|
||||||
VariableAvatarData,
|
VariableAvatarData,
|
||||||
AvatarAsChildFixes,
|
AvatarAsChildFixes,
|
||||||
StickAndBallDefaultAvatar
|
StickAndBallDefaultAvatar,
|
||||||
|
IdentityPacketsIncludeUpdateTime
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DomainConnectRequestVersion : PacketVersion {
|
enum class DomainConnectRequestVersion : PacketVersion {
|
||||||
|
|
|
@ -252,6 +252,8 @@ public:
|
||||||
|
|
||||||
void renderDebugMeshBoxes(gpu::Batch& batch);
|
void renderDebugMeshBoxes(gpu::Batch& batch);
|
||||||
|
|
||||||
|
int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); }
|
||||||
|
int getResourceDownloadAttemptsRemaining() { return _renderWatcher.getResourceDownloadAttemptsRemaining(); }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadURLFinished(bool success);
|
void loadURLFinished(bool success);
|
||||||
|
|
Loading…
Reference in a new issue