mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-16 22:30:42 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into removeLogSpam
Conflicts: libraries/networking/src/NodeList.cpp
This commit is contained in:
commit
9b11c7cc9c
14 changed files with 111 additions and 29 deletions
|
@ -16,6 +16,7 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QRegularExpression>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
|
@ -27,7 +28,6 @@
|
|||
#include <UUID.h>
|
||||
#include <TryLocker.h>
|
||||
|
||||
#include "AvatarMixerClientData.h"
|
||||
#include "AvatarMixer.h"
|
||||
|
||||
const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
|
||||
|
@ -67,6 +67,20 @@ AvatarMixer::~AvatarMixer() {
|
|||
// assuming 60 htz update rate.
|
||||
const float IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f;
|
||||
|
||||
void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
||||
QByteArray individualData = nodeData->getAvatar().identityByteArray();
|
||||
|
||||
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
|
||||
|
||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122());
|
||||
|
||||
identityPacket->write(individualData);
|
||||
|
||||
DependencyManager::get<NodeList>()->sendPacket(std::move(identityPacket), *destinationNode);
|
||||
|
||||
++_sumIdentityPackets;
|
||||
}
|
||||
|
||||
// NOTE: some additional optimizations to consider.
|
||||
// 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
|
||||
// if the avatar is not in view or in the keyhole.
|
||||
|
@ -227,6 +241,27 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
// setup a PacketList for the avatarPackets
|
||||
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
||||
|
||||
if (avatar.getSessionDisplayName().isEmpty() && // We haven't set it yet...
|
||||
nodeData->getReceivedIdentity()) { // ... but we have processed identity (with possible displayName).
|
||||
QString baseName = avatar.getDisplayName().trimmed();
|
||||
const QRegularExpression curses{ "fuck|shit|damn|cock|cunt" }; // POC. We may eventually want something much more elaborate (subscription?).
|
||||
baseName = baseName.replace(curses, "*"); // Replace rather than remove, so that people have a clue that the person's a jerk.
|
||||
const QRegularExpression trailingDigits{ "\\s*_\\d+$" }; // whitespace "_123"
|
||||
baseName = baseName.remove(trailingDigits);
|
||||
if (baseName.isEmpty()) {
|
||||
baseName = "anonymous";
|
||||
}
|
||||
|
||||
QPair<int, int>& soFar = _sessionDisplayNames[baseName]; // Inserts and answers 0, 0 if not already present, which is what we want.
|
||||
int& highWater = soFar.first;
|
||||
nodeData->setBaseDisplayName(baseName);
|
||||
avatar.setSessionDisplayName((highWater > 0) ? baseName + "_" + QString::number(highWater) : baseName);
|
||||
highWater++;
|
||||
soFar.second++; // refcount
|
||||
nodeData->flagIdentityChange();
|
||||
sendIdentityPacket(nodeData, node); // Tell new node about its sessionUUID. Others will find out below.
|
||||
}
|
||||
|
||||
// this is an AGENT we have received head data from
|
||||
// send back a packet with other active node data to this node
|
||||
nodeList->eachMatchingNode(
|
||||
|
@ -295,17 +330,7 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|
||||
|| distribution(generator) < IDENTITY_SEND_PROBABILITY)) {
|
||||
|
||||
QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
|
||||
|
||||
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
|
||||
|
||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122());
|
||||
|
||||
identityPacket->write(individualData);
|
||||
|
||||
nodeList->sendPacket(std::move(identityPacket), *node);
|
||||
|
||||
++_sumIdentityPackets;
|
||||
sendIdentityPacket(otherNodeData, node);
|
||||
}
|
||||
|
||||
AvatarData& otherAvatar = otherNodeData->getAvatar();
|
||||
|
@ -416,6 +441,16 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
|
|||
&& killedNode->getLinkedData()) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
{ // decrement sessionDisplayNames table and possibly remove
|
||||
QMutexLocker nodeDataLocker(&killedNode->getLinkedData()->getMutex());
|
||||
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(killedNode->getLinkedData());
|
||||
const QString& baseDisplayName = nodeData->getBaseDisplayName();
|
||||
// No sense guarding against very rare case of a node with no entry, as this will work without the guard and do one less lookup in the common case.
|
||||
if (--_sessionDisplayNames[baseDisplayName].second <= 0) {
|
||||
_sessionDisplayNames.remove(baseDisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
// this was an avatar we were sending to other people
|
||||
// send a kill packet for it to our other nodes
|
||||
auto killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason));
|
||||
|
@ -468,6 +503,7 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> mes
|
|||
if (avatar.processAvatarIdentity(identity)) {
|
||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||
nodeData->flagIdentityChange();
|
||||
nodeData->setReceivedIdentity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -564,7 +600,7 @@ void AvatarMixer::domainSettingsRequestComplete() {
|
|||
float domainMaximumScale = _domainMaximumScale;
|
||||
|
||||
nodeList->linkedDataCreateCallback = [domainMinimumScale, domainMaximumScale] (Node* node) {
|
||||
auto clientData = std::unique_ptr<AvatarMixerClientData> { new AvatarMixerClientData };
|
||||
auto clientData = std::unique_ptr<AvatarMixerClientData> { new AvatarMixerClientData(node->getUUID()) };
|
||||
clientData->getAvatar().setDomainMinimumScale(domainMinimumScale);
|
||||
clientData->getAvatar().setDomainMaximumScale(domainMaximumScale);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
#include "AvatarMixerClientData.h"
|
||||
|
||||
/// Handles assignments of type AvatarMixer - distribution of avatar data to various clients
|
||||
class AvatarMixer : public ThreadedAssignment {
|
||||
|
@ -46,6 +47,7 @@ private slots:
|
|||
private:
|
||||
void broadcastAvatarData();
|
||||
void parseDomainServerSettings(const QJsonObject& domainSettings);
|
||||
void sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode);
|
||||
|
||||
QThread _broadcastThread;
|
||||
|
||||
|
@ -64,6 +66,8 @@ private:
|
|||
float _domainMaximumScale { MAX_AVATAR_SCALE };
|
||||
|
||||
QTimer* _broadcastTimer = nullptr;
|
||||
|
||||
QHash<QString, QPair<int, int>> _sessionDisplayNames;
|
||||
};
|
||||
|
||||
#endif // hifi_AvatarMixer_h
|
||||
|
|
|
@ -34,6 +34,8 @@ const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps";
|
|||
class AvatarMixerClientData : public NodeData {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AvatarMixerClientData(const QUuid& nodeID = QUuid()) : NodeData(nodeID) {}
|
||||
virtual ~AvatarMixerClientData() {}
|
||||
using HRCTime = p_high_resolution_clock::time_point;
|
||||
|
||||
int parseData(ReceivedMessage& message) override;
|
||||
|
@ -50,6 +52,8 @@ public:
|
|||
|
||||
HRCTime getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
|
||||
void flagIdentityChange() { _identityChangeTimestamp = p_high_resolution_clock::now(); }
|
||||
bool getReceivedIdentity() const { return _gotIdentity; }
|
||||
void setReceivedIdentity() { _gotIdentity = true; }
|
||||
|
||||
void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; }
|
||||
float getFullRateDistance() const { return _fullRateDistance; }
|
||||
|
@ -87,6 +91,9 @@ public:
|
|||
void removeFromRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.erase(other); }
|
||||
void ignoreOther(SharedNodePointer self, SharedNodePointer other);
|
||||
|
||||
const QString& getBaseDisplayName() { return _baseDisplayName; }
|
||||
void setBaseDisplayName(const QString& baseDisplayName) { _baseDisplayName = baseDisplayName; }
|
||||
|
||||
private:
|
||||
AvatarSharedPointer _avatar { new AvatarData() };
|
||||
|
||||
|
@ -95,6 +102,7 @@ private:
|
|||
std::unordered_set<QUuid> _hasReceivedFirstPacketsFrom;
|
||||
|
||||
HRCTime _identityChangeTimestamp;
|
||||
bool _gotIdentity { false };
|
||||
|
||||
float _fullRateDistance = FLT_MAX;
|
||||
float _maxAvatarDistance = FLT_MAX;
|
||||
|
@ -108,6 +116,8 @@ private:
|
|||
|
||||
SimpleMovingAverage _avgOtherAvatarDataRate;
|
||||
std::unordered_set<QUuid> _radiusIgnoredOthers;
|
||||
|
||||
QString _baseDisplayName{}; // The santized key used in determinging unique sessionDisplayName, so that we can remove from dictionary.
|
||||
};
|
||||
|
||||
#endif // hifi_AvatarMixerClientData_h
|
||||
|
|
|
@ -800,7 +800,12 @@ void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPoin
|
|||
usernameFromIDReplyPacket->write(nodeUUID.toRfc4122());
|
||||
usernameFromIDReplyPacket->writeString(verifiedUsername);
|
||||
|
||||
qDebug() << "Sending username" << verifiedUsername << "associated with node" << nodeUUID;
|
||||
// now put in the machine fingerprint
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData());
|
||||
QUuid machineFingerprint = nodeData ? nodeData->getMachineFingerprint() : QUuid();
|
||||
usernameFromIDReplyPacket->write(machineFingerprint.toRfc4122());
|
||||
|
||||
qDebug() << "Sending username" << verifiedUsername << "and machine fingerprint" << machineFingerprint << "associated with node" << nodeUUID;
|
||||
|
||||
// Ship it!
|
||||
limitedNodeList->sendPacket(std::move(usernameFromIDReplyPacket), *sendingNode);
|
||||
|
|
|
@ -119,6 +119,7 @@ public:
|
|||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
|
||||
|
||||
void setShowDisplayName(bool showDisplayName);
|
||||
virtual void setSessionDisplayName(const QString& sessionDisplayName) override { }; // no-op
|
||||
|
||||
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
|
||||
|
||||
|
@ -189,6 +190,10 @@ public slots:
|
|||
protected:
|
||||
friend class AvatarManager;
|
||||
|
||||
virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send.
|
||||
QString _empty{};
|
||||
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
|
||||
|
||||
void setMotionState(AvatarMotionState* motionState);
|
||||
|
||||
SkeletonModelPointer _skeletonModel;
|
||||
|
|
|
@ -984,7 +984,7 @@ QStringList AvatarData::getJointNames() const {
|
|||
void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) {
|
||||
QDataStream packetStream(data);
|
||||
|
||||
packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.avatarEntityData;
|
||||
packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.sessionDisplayName >> identityOut.avatarEntityData;
|
||||
}
|
||||
|
||||
static const QUrl emptyURL("");
|
||||
|
@ -1006,6 +1006,7 @@ bool AvatarData::processAvatarIdentity(const Identity& identity) {
|
|||
setDisplayName(identity.displayName);
|
||||
hasIdentityChanged = true;
|
||||
}
|
||||
maybeUpdateSessionDisplayNameFromTransport(identity.sessionDisplayName);
|
||||
|
||||
if (identity.attachmentData != _attachmentData) {
|
||||
setAttachmentData(identity.attachmentData);
|
||||
|
@ -1030,7 +1031,7 @@ QByteArray AvatarData::identityByteArray() {
|
|||
const QUrl& urlToSend = cannonicalSkeletonModelURL(emptyURL);
|
||||
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << _avatarEntityData;
|
||||
identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << getSessionDisplayNameForTransport() << _avatarEntityData;
|
||||
});
|
||||
|
||||
return identityData;
|
||||
|
@ -1385,6 +1386,7 @@ static const QString JSON_AVATAR_HEAD = QStringLiteral("head");
|
|||
static const QString JSON_AVATAR_HEAD_MODEL = QStringLiteral("headModel");
|
||||
static const QString JSON_AVATAR_BODY_MODEL = QStringLiteral("bodyModel");
|
||||
static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
|
||||
// It isn't meaningful to persist sessionDisplayName.
|
||||
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
|
||||
static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities");
|
||||
static const QString JSON_AVATAR_SCALE = QStringLiteral("scale");
|
||||
|
|
|
@ -171,6 +171,9 @@ class AvatarData : public QObject, public SpatiallyNestable {
|
|||
Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness)
|
||||
|
||||
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName)
|
||||
// sessionDisplayName is sanitized, defaulted version displayName that is defined by the AvatarMixer rather than by Interface clients.
|
||||
// The result is unique among all avatars present at the time.
|
||||
Q_PROPERTY(QString sessionDisplayName READ getSessionDisplayName WRITE setSessionDisplayName)
|
||||
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript)
|
||||
Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData WRITE setAttachmentData)
|
||||
|
||||
|
@ -313,6 +316,7 @@ public:
|
|||
QUrl skeletonModelURL;
|
||||
QVector<AttachmentData> attachmentData;
|
||||
QString displayName;
|
||||
QString sessionDisplayName;
|
||||
AvatarEntityMap avatarEntityData;
|
||||
};
|
||||
|
||||
|
@ -325,9 +329,11 @@ public:
|
|||
|
||||
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
|
||||
const QString& getDisplayName() const { return _displayName; }
|
||||
const QString& getSessionDisplayName() const { return _sessionDisplayName; }
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
virtual void setDisplayName(const QString& displayName);
|
||||
virtual void setSessionDisplayName(const QString& sessionDisplayName) { _sessionDisplayName = sessionDisplayName; };
|
||||
|
||||
Q_INVOKABLE QVector<AttachmentData> getAttachmentData() const;
|
||||
Q_INVOKABLE virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
|
||||
|
@ -390,6 +396,8 @@ public slots:
|
|||
|
||||
protected:
|
||||
glm::vec3 _handPosition;
|
||||
virtual const QString& getSessionDisplayNameForTransport() const { return _sessionDisplayName; }
|
||||
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) { } // No-op in AvatarMixer
|
||||
|
||||
// Body scale
|
||||
float _targetScale;
|
||||
|
@ -417,6 +425,7 @@ protected:
|
|||
QUrl _skeletonFBXURL;
|
||||
QVector<AttachmentData> _attachmentData;
|
||||
QString _displayName;
|
||||
QString _sessionDisplayName { };
|
||||
const QUrl& cannonicalSkeletonModelURL(const QUrl& empty);
|
||||
|
||||
float _displayNameTargetAlpha;
|
||||
|
|
|
@ -133,6 +133,13 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
|
|||
|
||||
// make sure this isn't for an ignored avatar
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
static auto EMPTY = QUuid();
|
||||
if (identity.uuid == _avatarHash.value(EMPTY)->getSessionUUID()) {
|
||||
// We add MyAvatar to _avatarHash with an empty UUID. Code relies on this. In order to correctly handle an
|
||||
// identity packet for ourself (such as when we are assigned a sessionDisplayName by the mixer upon joining),
|
||||
// we make things match here.
|
||||
identity.uuid = EMPTY;
|
||||
}
|
||||
if (!nodeList->isIgnoringNode(identity.uuid)) {
|
||||
// mesh URL for a UUID, find avatar in our list
|
||||
auto avatar = newOrExistingAvatar(identity.uuid, sendingNode);
|
||||
|
|
|
@ -923,8 +923,10 @@ void NodeList::processUsernameFromIDReply(QSharedPointer<ReceivedMessage> messag
|
|||
QString nodeUUIDString = (QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID))).toString();
|
||||
// read the username from the packet
|
||||
QString username = message->readString();
|
||||
// read the machine fingerprint from the packet
|
||||
QString machineFingerprintString = (QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID))).toString();
|
||||
|
||||
qCDebug(networking) << "Got username" << username << "for node" << nodeUUIDString;
|
||||
qCDebug(networking) << "Got username" << username << "and machine fingerprint" << machineFingerprintString << "for node" << nodeUUIDString;
|
||||
|
||||
emit usernameFromIDReply(nodeUUIDString, username);
|
||||
emit usernameFromIDReply(nodeUUIDString, username, machineFingerprintString);
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ signals:
|
|||
void receivedDomainServerList();
|
||||
void ignoredNode(const QUuid& nodeID);
|
||||
void ignoreRadiusEnabledChanged(bool isIgnored);
|
||||
void usernameFromIDReply(const QString& nodeID, const QString& username);
|
||||
void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint);
|
||||
|
||||
private slots:
|
||||
void stopKeepalivePingTimer();
|
||||
|
|
|
@ -44,7 +44,7 @@ const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
|
|||
PacketVersion versionForPacketType(PacketType packetType) {
|
||||
switch (packetType) {
|
||||
case PacketType::DomainList:
|
||||
return static_cast<PacketVersion>(DomainListVersion::GetUsernameFromUUIDSupport);
|
||||
return static_cast<PacketVersion>(DomainListVersion::GetMachineFingerprintFromUUIDSupport);
|
||||
case PacketType::EntityAdd:
|
||||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
|
@ -53,7 +53,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::AvatarData:
|
||||
case PacketType::BulkAvatarData:
|
||||
case PacketType::KillAvatar:
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::HasKillAvatarReason);
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SessionDisplayName);
|
||||
case PacketType::ICEServerHeartbeat:
|
||||
return 18; // ICE Server Heartbeat signing
|
||||
case PacketType::AssetGetInfo:
|
||||
|
|
|
@ -205,7 +205,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
|||
AbsoluteSixByteRotations,
|
||||
SensorToWorldMat,
|
||||
HandControllerJoints,
|
||||
HasKillAvatarReason
|
||||
HasKillAvatarReason,
|
||||
SessionDisplayName
|
||||
};
|
||||
|
||||
enum class DomainConnectRequestVersion : PacketVersion {
|
||||
|
@ -230,7 +231,8 @@ enum class DomainServerAddedNodeVersion : PacketVersion {
|
|||
enum class DomainListVersion : PacketVersion {
|
||||
PrePermissionsGrid = 18,
|
||||
PermissionsGrid,
|
||||
GetUsernameFromUUIDSupport
|
||||
GetUsernameFromUUIDSupport,
|
||||
GetMachineFingerprintFromUUIDSupport
|
||||
};
|
||||
|
||||
enum class AudioVersion : PacketVersion {
|
||||
|
|
|
@ -101,10 +101,10 @@ signals:
|
|||
void enteredIgnoreRadius();
|
||||
|
||||
/**jsdoc
|
||||
* Notifies scripts of the username associated with a UUID.
|
||||
* @function Users.enteredIgnoreRadius
|
||||
* Notifies scripts of the username and machine fingerprint associated with a UUID.
|
||||
* @function Users.usernameFromIDReply
|
||||
*/
|
||||
void usernameFromIDReply(const QString& nodeID, const QString& username);
|
||||
void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ function populateUserList() {
|
|||
AvatarList.getAvatarIdentifiers().sort().forEach(function (id) { // sorting the identifiers is just an aid for debugging
|
||||
var avatar = AvatarList.getAvatar(id);
|
||||
var avatarPalDatum = {
|
||||
displayName: avatar.displayName || ('anonymous ' + counter++),
|
||||
displayName: avatar.sessionDisplayName,
|
||||
userName: '',
|
||||
sessionId: id || ''
|
||||
};
|
||||
|
@ -137,7 +137,7 @@ function populateUserList() {
|
|||
}
|
||||
|
||||
// The function that handles the reply from the server
|
||||
function usernameFromIDReply(id, username) {
|
||||
function usernameFromIDReply(id, username, machineFingerprint) {
|
||||
var data;
|
||||
// If the ID we've received is our ID...
|
||||
if (AvatarList.getAvatar('').sessionUUID === id) {
|
||||
|
@ -145,7 +145,7 @@ function usernameFromIDReply(id, username) {
|
|||
data = ['', username + ' (hidden)']
|
||||
} else {
|
||||
// Set the data to contain the ID and the username+ID concat string.
|
||||
data = [id, username + '/' + id];
|
||||
data = [id, username + '/' + machineFingerprint];
|
||||
}
|
||||
print('Username Data:', JSON.stringify(data));
|
||||
// Ship the data off to QML
|
||||
|
|
Loading…
Reference in a new issue