Merge pull request #2691 from birarda/agent-avatar-manager

expose AvatarHashMap to Agent for Avatar querying from assignment-client
This commit is contained in:
AndrewMeadows 2014-04-18 09:58:34 -07:00
commit 220c9c40f3
12 changed files with 223 additions and 140 deletions

View file

@ -33,7 +33,8 @@ Agent::Agent(const QByteArray& packet) :
ThreadedAssignment(packet), ThreadedAssignment(packet),
_voxelEditSender(), _voxelEditSender(),
_particleEditSender(), _particleEditSender(),
_receivedAudioBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO) _receivedAudioBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO),
_avatarHashMap()
{ {
// be the parent of the script engine so it gets moved when we do // be the parent of the script engine so it gets moved when we do
_scriptEngine.setParent(this); _scriptEngine.setParent(this);
@ -131,6 +132,16 @@ void Agent::readPendingDatagrams() {
// let this continue through to the NodeList so it updates last heard timestamp // let this continue through to the NodeList so it updates last heard timestamp
// for the sending audio mixer // for the sending audio mixer
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket); NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
} else if (datagramPacketType == PacketTypeBulkAvatarData
|| datagramPacketType == PacketTypeAvatarIdentity
|| datagramPacketType == PacketTypeAvatarBillboard
|| datagramPacketType == PacketTypeKillAvatar) {
// let the avatar hash map process it
_avatarHashMap.processAvatarMixerDatagram(receivedPacket, nodeList->sendingNodeForPacket(receivedPacket));
// let this continue through to the NodeList so it updates last heard timestamp
// for the sending avatar-mixer
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
} else { } else {
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket); NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
} }
@ -191,6 +202,7 @@ void Agent::run() {
// give this AvatarData object to the script engine // give this AvatarData object to the script engine
_scriptEngine.setAvatarData(&scriptedAvatar, "Avatar"); _scriptEngine.setAvatarData(&scriptedAvatar, "Avatar");
_scriptEngine.setAvatarHashMap(&_avatarHashMap, "AvatarList");
// register ourselves to the script engine // register ourselves to the script engine
_scriptEngine.registerGlobalObject("Agent", this); _scriptEngine.registerGlobalObject("Agent", this);

View file

@ -18,6 +18,7 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <AvatarHashMap.h>
#include <MixedAudioRingBuffer.h> #include <MixedAudioRingBuffer.h>
#include <ParticleEditPacketSender.h> #include <ParticleEditPacketSender.h>
#include <ParticleTree.h> #include <ParticleTree.h>
@ -65,6 +66,7 @@ private:
VoxelTreeHeadlessViewer _voxelViewer; VoxelTreeHeadlessViewer _voxelViewer;
MixedAudioRingBuffer _receivedAudioBuffer; MixedAudioRingBuffer _receivedAudioBuffer;
AvatarHashMap _avatarHashMap;
}; };
#endif // hifi_Agent_h #endif // hifi_Agent_h

View file

@ -56,7 +56,6 @@ Avatar::Avatar() :
_mouseRayOrigin(0.0f, 0.0f, 0.0f), _mouseRayOrigin(0.0f, 0.0f, 0.0f),
_mouseRayDirection(0.0f, 0.0f, 0.0f), _mouseRayDirection(0.0f, 0.0f, 0.0f),
_moving(false), _moving(false),
_owningAvatarMixer(),
_collisionFlags(0), _collisionFlags(0),
_initialized(false), _initialized(false),
_shouldRenderBillboard(true) _shouldRenderBillboard(true)
@ -685,6 +684,11 @@ void Avatar::setBillboard(const QByteArray& billboard) {
} }
int Avatar::parseDataAtOffset(const QByteArray& packet, int offset) { int Avatar::parseDataAtOffset(const QByteArray& packet, int offset) {
if (!_initialized) {
// now that we have data for this Avatar we are go for init
init();
}
// change in position implies movement // change in position implies movement
glm::vec3 oldPosition = _position; glm::vec3 oldPosition = _position;

View file

@ -99,9 +99,6 @@ public:
/// Returns the distance to use as a LOD parameter. /// Returns the distance to use as a LOD parameter.
float getLODDistance() const; float getLODDistance() const;
Node* getOwningAvatarMixer() { return _owningAvatarMixer.data(); }
void setOwningAvatarMixer(const QWeakPointer<Node>& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
@ -177,7 +174,6 @@ protected:
glm::vec3 _mouseRayDirection; glm::vec3 _mouseRayDirection;
float _stringLength; float _stringLength;
bool _moving; ///< set when position is changing bool _moving; ///< set when position is changing
QWeakPointer<Node> _owningAvatarMixer;
uint32_t _collisionFlags; uint32_t _collisionFlags;

View file

@ -51,14 +51,16 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
// simulate avatars // simulate avatars
AvatarHash::iterator avatarIterator = _avatarHash.begin(); AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) { while (avatarIterator != _avatarHash.end()) {
Avatar* avatar = static_cast<Avatar*>(avatarIterator.value().data()); AvatarSharedPointer sharedAvatar = avatarIterator.value();
if (avatar == static_cast<Avatar*>(_myAvatar.data()) || !avatar->isInitialized()) { Avatar* avatar = reinterpret_cast<Avatar*>(sharedAvatar.data());
if (sharedAvatar == _myAvatar || !avatar->isInitialized()) {
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop. // DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
// DO NOT update uninitialized Avatars // DO NOT update uninitialized Avatars
++avatarIterator; ++avatarIterator;
continue; continue;
} }
if (avatar->getOwningAvatarMixer()) { if (!shouldKillAvatar(sharedAvatar)) {
// this avatar's mixer is still around, go ahead and simulate it // this avatar's mixer is still around, go ahead and simulate it
avatar->simulate(deltaTime); avatar->simulate(deltaTime);
avatar->setMouseRay(mouseOrigin, mouseDirection); avatar->setMouseRay(mouseOrigin, mouseDirection);
@ -127,127 +129,12 @@ void AvatarManager::renderAvatarFades(const glm::vec3& cameraPosition, Avatar::R
} }
} }
AvatarSharedPointer AvatarManager::matchingOrNewAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) { AvatarSharedPointer AvatarManager::newSharedAvatar() {
AvatarSharedPointer matchingAvatar = _avatarHash.value(sessionUUID); return AvatarSharedPointer(new Avatar());
if (!matchingAvatar) {
// construct a new Avatar for this node
Avatar* avatar = new Avatar();
avatar->setOwningAvatarMixer(mixerWeakPointer);
// insert the new avatar into our hash
matchingAvatar = AvatarSharedPointer(avatar);
_avatarHash.insert(sessionUUID, matchingAvatar);
qDebug() << "Adding avatar with sessionUUID " << sessionUUID << "to AvatarManager hash.";
}
return matchingAvatar;
}
void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer) {
switch (packetTypeForPacket(datagram)) {
case PacketTypeBulkAvatarData:
processAvatarDataPacket(datagram, mixerWeakPointer);
break;
case PacketTypeAvatarIdentity:
processAvatarIdentityPacket(datagram, mixerWeakPointer);
break;
case PacketTypeAvatarBillboard:
processAvatarBillboardPacket(datagram, mixerWeakPointer);
break;
case PacketTypeKillAvatar:
processKillAvatar(datagram);
break;
default:
break;
}
}
void AvatarManager::processAvatarDataPacket(const QByteArray &datagram, const QWeakPointer<Node> &mixerWeakPointer) {
int bytesRead = numBytesForPacketHeader(datagram);
// enumerate over all of the avatars in this packet
// only add them if mixerWeakPointer points to something (meaning that mixer is still around)
while (bytesRead < datagram.size() && mixerWeakPointer.data()) {
QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(bytesRead, NUM_BYTES_RFC4122_UUID));
bytesRead += NUM_BYTES_RFC4122_UUID;
AvatarSharedPointer matchingAvatarData = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
// have the matching (or new) avatar parse the data from the packet
bytesRead += matchingAvatarData->parseDataAtOffset(datagram, bytesRead);
Avatar* matchingAvatar = reinterpret_cast<Avatar*>(matchingAvatarData.data());
if (!matchingAvatar->isInitialized()) {
// now that we have AvatarData for this Avatar we are go for init
matchingAvatar->init();
}
}
}
void AvatarManager::processAvatarIdentityPacket(const QByteArray &packet, const QWeakPointer<Node>& mixerWeakPointer) {
// setup a data stream to parse the packet
QDataStream identityStream(packet);
identityStream.skipRawData(numBytesForPacketHeader(packet));
QUuid sessionUUID;
while (!identityStream.atEnd()) {
QUrl faceMeshURL, skeletonURL;
QString displayName;
identityStream >> sessionUUID >> faceMeshURL >> skeletonURL >> displayName;
// mesh URL for a UUID, find avatar in our list
AvatarSharedPointer matchingAvatar = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
if (matchingAvatar) {
Avatar* avatar = static_cast<Avatar*>(matchingAvatar.data());
if (avatar->getFaceModelURL() != faceMeshURL) {
avatar->setFaceModelURL(faceMeshURL);
}
if (avatar->getSkeletonModelURL() != skeletonURL) {
avatar->setSkeletonModelURL(skeletonURL);
}
if (avatar->getDisplayName() != displayName) {
avatar->setDisplayName(displayName);
}
}
}
}
void AvatarManager::processAvatarBillboardPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer) {
int headerSize = numBytesForPacketHeader(packet);
QUuid sessionUUID = QUuid::fromRfc4122(QByteArray::fromRawData(packet.constData() + headerSize, NUM_BYTES_RFC4122_UUID));
AvatarSharedPointer matchingAvatar = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
if (matchingAvatar) {
Avatar* avatar = static_cast<Avatar*>(matchingAvatar.data());
QByteArray billboard = packet.mid(headerSize + NUM_BYTES_RFC4122_UUID);
if (avatar->getBillboard() != billboard) {
avatar->setBillboard(billboard);
}
}
}
void AvatarManager::processKillAvatar(const QByteArray& datagram) {
// read the node id
QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(numBytesForPacketHeader(datagram), NUM_BYTES_RFC4122_UUID));
// remove the avatar with that UUID from our hash, if it exists
AvatarHash::iterator matchedAvatar = _avatarHash.find(sessionUUID);
if (matchedAvatar != _avatarHash.end()) {
erase(matchedAvatar);
}
} }
AvatarHash::iterator AvatarManager::erase(const AvatarHash::iterator& iterator) { AvatarHash::iterator AvatarManager::erase(const AvatarHash::iterator& iterator) {
if (iterator.key() != MY_AVATAR_KEY) { if (iterator.key() != MY_AVATAR_KEY) {
qDebug() << "Removing Avatar with UUID" << iterator.key() << "from AvatarManager hash.";
if (reinterpret_cast<Avatar*>(iterator.value().data())->isInitialized()) { if (reinterpret_cast<Avatar*>(iterator.value().data())->isInitialized()) {
_avatarFades.push_back(iterator.value()); _avatarFades.push_back(iterator.value());
} }

View file

@ -22,7 +22,7 @@
class MyAvatar; class MyAvatar;
class AvatarManager : public QObject, public AvatarHashMap { class AvatarManager : public AvatarHashMap {
Q_OBJECT Q_OBJECT
public: public:
AvatarManager(QObject* parent = 0); AvatarManager(QObject* parent = 0);
@ -35,23 +35,15 @@ public:
void renderAvatars(Avatar::RenderMode renderMode, bool selfAvatarOnly = false); void renderAvatars(Avatar::RenderMode renderMode, bool selfAvatarOnly = false);
void clearOtherAvatars(); void clearOtherAvatars();
public slots:
void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer);
private: private:
AvatarManager(const AvatarManager& other); AvatarManager(const AvatarManager& other);
AvatarSharedPointer matchingOrNewAvatar(const QUuid& nodeUUID, const QWeakPointer<Node>& mixerWeakPointer);
void processAvatarDataPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processAvatarIdentityPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processAvatarBillboardPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processKillAvatar(const QByteArray& datagram);
void simulateAvatarFades(float deltaTime); void simulateAvatarFades(float deltaTime);
void renderAvatarFades(const glm::vec3& cameraPosition, Avatar::RenderMode renderMode); void renderAvatarFades(const glm::vec3& cameraPosition, Avatar::RenderMode renderMode);
AvatarSharedPointer newSharedAvatar();
// virtual override // virtual override
AvatarHash::iterator erase(const AvatarHash::iterator& iterator); AvatarHash::iterator erase(const AvatarHash::iterator& iterator);

View file

@ -51,7 +51,9 @@ AvatarData::AvatarData() :
_displayNameTargetAlpha(0.0f), _displayNameTargetAlpha(0.0f),
_displayNameAlpha(0.0f), _displayNameAlpha(0.0f),
_billboard(), _billboard(),
_errorLogExpiry(0) _errorLogExpiry(0),
_owningAvatarMixer(),
_lastUpdateTimer()
{ {
} }
@ -193,6 +195,10 @@ bool AvatarData::shouldLogError(const quint64& now) {
// read data in packet starting at byte offset and return number of bytes parsed // read data in packet starting at byte offset and return number of bytes parsed
int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
// reset the last heard timer since we have new data for this AvatarData
_lastUpdateTimer.restart();
// lazily allocate memory for HeadData in case we're not an Avatar instance // lazily allocate memory for HeadData in case we're not an Avatar instance
if (!_headData) { if (!_headData) {
_headData = new HeadData(this); _headData = new HeadData(this);

View file

@ -32,6 +32,7 @@ typedef unsigned long long quint64;
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include <QtCore/QElapsedTimer>
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QObject> #include <QtCore/QObject>
@ -44,6 +45,7 @@ typedef unsigned long long quint64;
#include <CollisionInfo.h> #include <CollisionInfo.h>
#include <RegisteredMetaTypes.h> #include <RegisteredMetaTypes.h>
#include <Node.h>
#include "HeadData.h" #include "HeadData.h"
#include "HandData.h" #include "HandData.h"
@ -220,6 +222,11 @@ public:
QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); } QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); }
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); } void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }
Node* getOwningAvatarMixer() { return _owningAvatarMixer.data(); }
void setOwningAvatarMixer(const QWeakPointer<Node>& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
QElapsedTimer& getLastUpdateTimer() { return _lastUpdateTimer; }
virtual float getBoundingRadius() const { return 1.f; } virtual float getBoundingRadius() const { return 1.f; }
static void setNetworkAccessManager(QNetworkAccessManager* sharedAccessManager) { networkAccessManager = sharedAccessManager; } static void setNetworkAccessManager(QNetworkAccessManager* sharedAccessManager) { networkAccessManager = sharedAccessManager; }
@ -278,7 +285,10 @@ protected:
static QNetworkAccessManager* networkAccessManager; static QNetworkAccessManager* networkAccessManager;
quint64 _errorLogExpiry; ///< time in future when to log an error quint64 _errorLogExpiry; ///< time in future when to log an error
QWeakPointer<Node> _owningAvatarMixer;
QElapsedTimer _lastUpdateTimer;
/// Loads the joint indices, names from the FST file (if any) /// Loads the joint indices, names from the FST file (if any)
virtual void updateJointMappings(); virtual void updateJointMappings();

View file

@ -9,11 +9,14 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <PacketHeaders.h>
#include "AvatarHashMap.h" #include "AvatarHashMap.h"
AvatarHashMap::AvatarHashMap() : AvatarHashMap::AvatarHashMap() :
_avatarHash() _avatarHash()
{ {
} }
void AvatarHashMap::insert(const QUuid& id, AvatarSharedPointer avatar) { void AvatarHashMap::insert(const QUuid& id, AvatarSharedPointer avatar) {
@ -22,6 +25,150 @@ void AvatarHashMap::insert(const QUuid& id, AvatarSharedPointer avatar) {
} }
AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator) { AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator) {
qDebug() << "Removing Avatar with UUID" << iterator.key() << "from AvatarHashMap.";
return _avatarHash.erase(iterator); return _avatarHash.erase(iterator);
} }
const qint64 AVATAR_SILENCE_THRESHOLD_MSECS = 5 * 1000;
bool AvatarHashMap::shouldKillAvatar(const AvatarSharedPointer& sharedAvatar) {
return (sharedAvatar->getOwningAvatarMixer() == NULL
|| sharedAvatar->getLastUpdateTimer().elapsed() > AVATAR_SILENCE_THRESHOLD_MSECS);
}
void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer) {
switch (packetTypeForPacket(datagram)) {
case PacketTypeBulkAvatarData:
processAvatarDataPacket(datagram, mixerWeakPointer);
break;
case PacketTypeAvatarIdentity:
processAvatarIdentityPacket(datagram, mixerWeakPointer);
break;
case PacketTypeAvatarBillboard:
processAvatarBillboardPacket(datagram, mixerWeakPointer);
break;
case PacketTypeKillAvatar:
processKillAvatar(datagram);
break;
default:
break;
}
}
bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) {
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {
AvatarSharedPointer sharedAvatar = avatarIterator.value();
if (avatarIterator.value()->getDisplayName() == displayName) {
// this is a match
// check if this avatar should still be around
if (!shouldKillAvatar(sharedAvatar)) {
// we have a match, return true
return true;
} else {
// we should remove this avatar, do that now
erase(avatarIterator);
}
break;
} else {
++avatarIterator;
}
}
// return false, no match
return false;
}
AvatarSharedPointer AvatarHashMap::newSharedAvatar() {
return AvatarSharedPointer(new AvatarData());
}
AvatarSharedPointer AvatarHashMap::matchingOrNewAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
AvatarSharedPointer matchingAvatar = _avatarHash.value(sessionUUID);
if (!matchingAvatar) {
// insert the new avatar into our hash
matchingAvatar = newSharedAvatar();
qDebug() << "Adding avatar with sessionUUID " << sessionUUID << "to AvatarHashMap.";
_avatarHash.insert(sessionUUID, matchingAvatar);
matchingAvatar->setOwningAvatarMixer(mixerWeakPointer);
}
return matchingAvatar;
}
void AvatarHashMap::processAvatarDataPacket(const QByteArray &datagram, const QWeakPointer<Node> &mixerWeakPointer) {
int bytesRead = numBytesForPacketHeader(datagram);
// enumerate over all of the avatars in this packet
// only add them if mixerWeakPointer points to something (meaning that mixer is still around)
while (bytesRead < datagram.size() && mixerWeakPointer.data()) {
QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(bytesRead, NUM_BYTES_RFC4122_UUID));
bytesRead += NUM_BYTES_RFC4122_UUID;
AvatarSharedPointer matchingAvatarData = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
// have the matching (or new) avatar parse the data from the packet
bytesRead += matchingAvatarData->parseDataAtOffset(datagram, bytesRead);
}
}
void AvatarHashMap::processAvatarIdentityPacket(const QByteArray &packet, const QWeakPointer<Node>& mixerWeakPointer) {
// setup a data stream to parse the packet
QDataStream identityStream(packet);
identityStream.skipRawData(numBytesForPacketHeader(packet));
QUuid sessionUUID;
while (!identityStream.atEnd()) {
QUrl faceMeshURL, skeletonURL;
QString displayName;
identityStream >> sessionUUID >> faceMeshURL >> skeletonURL >> displayName;
// mesh URL for a UUID, find avatar in our list
AvatarSharedPointer matchingAvatar = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
if (matchingAvatar) {
if (matchingAvatar->getFaceModelURL() != faceMeshURL) {
matchingAvatar->setFaceModelURL(faceMeshURL);
}
if (matchingAvatar->getSkeletonModelURL() != skeletonURL) {
matchingAvatar->setSkeletonModelURL(skeletonURL);
}
if (matchingAvatar->getDisplayName() != displayName) {
matchingAvatar->setDisplayName(displayName);
}
}
}
}
void AvatarHashMap::processAvatarBillboardPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer) {
int headerSize = numBytesForPacketHeader(packet);
QUuid sessionUUID = QUuid::fromRfc4122(QByteArray::fromRawData(packet.constData() + headerSize, NUM_BYTES_RFC4122_UUID));
AvatarSharedPointer matchingAvatar = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
if (matchingAvatar) {
QByteArray billboard = packet.mid(headerSize + NUM_BYTES_RFC4122_UUID);
if (matchingAvatar->getBillboard() != billboard) {
matchingAvatar->setBillboard(billboard);
}
}
}
void AvatarHashMap::processKillAvatar(const QByteArray& datagram) {
// read the node id
QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(numBytesForPacketHeader(datagram), NUM_BYTES_RFC4122_UUID));
// remove the avatar with that UUID from our hash, if it exists
AvatarHash::iterator matchedAvatar = _avatarHash.find(sessionUUID);
if (matchedAvatar != _avatarHash.end()) {
erase(matchedAvatar);
}
}

View file

@ -16,12 +16,15 @@
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
#include <QtCore/QUuid> #include <QtCore/QUuid>
#include <Node.h>
#include "AvatarData.h" #include "AvatarData.h"
typedef QSharedPointer<AvatarData> AvatarSharedPointer; typedef QSharedPointer<AvatarData> AvatarSharedPointer;
typedef QHash<QUuid, AvatarSharedPointer> AvatarHash; typedef QHash<QUuid, AvatarSharedPointer> AvatarHash;
class AvatarHashMap { class AvatarHashMap : public QObject {
Q_OBJECT
public: public:
AvatarHashMap(); AvatarHashMap();
@ -29,9 +32,23 @@ public:
int size() const { return _avatarHash.size(); } int size() const { return _avatarHash.size(); }
virtual void insert(const QUuid& id, AvatarSharedPointer avatar); virtual void insert(const QUuid& id, AvatarSharedPointer avatar);
public slots:
void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer);
bool containsAvatarWithDisplayName(const QString& displayName);
protected: protected:
virtual AvatarHash::iterator erase(const AvatarHash::iterator& iterator); virtual AvatarHash::iterator erase(const AvatarHash::iterator& iterator);
bool shouldKillAvatar(const AvatarSharedPointer& sharedAvatar);
virtual AvatarSharedPointer newSharedAvatar();
AvatarSharedPointer matchingOrNewAvatar(const QUuid& nodeUUID, const QWeakPointer<Node>& mixerWeakPointer);
void processAvatarDataPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processAvatarIdentityPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processAvatarBillboardPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processKillAvatar(const QByteArray& datagram);
AvatarHash _avatarHash; AvatarHash _avatarHash;
}; };

View file

@ -156,6 +156,14 @@ void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectNa
registerGlobalObject(objectName, _avatarData); registerGlobalObject(objectName, _avatarData);
} }
void ScriptEngine::setAvatarHashMap(AvatarHashMap* avatarHashMap, const QString& objectName) {
// remove the old Avatar property, if it exists
_engine.globalObject().setProperty(objectName, QScriptValue());
// give the script engine the new avatar hash map
registerGlobalObject(objectName, avatarHashMap);
}
bool ScriptEngine::setScriptContents(const QString& scriptContents, const QString& fileNameString) { bool ScriptEngine::setScriptContents(const QString& scriptContents, const QString& fileNameString) {
if (_isRunning) { if (_isRunning) {
return false; return false;

View file

@ -22,6 +22,7 @@
#include <VoxelsScriptingInterface.h> #include <VoxelsScriptingInterface.h>
#include <AvatarData.h> #include <AvatarData.h>
#include <AvatarHashMap.h>
#include "AnimationCache.h" #include "AnimationCache.h"
#include "AbstractControllerScriptingInterface.h" #include "AbstractControllerScriptingInterface.h"
@ -63,6 +64,7 @@ public:
bool isAvatar() const { return _isAvatar; } bool isAvatar() const { return _isAvatar; }
void setAvatarData(AvatarData* avatarData, const QString& objectName); void setAvatarData(AvatarData* avatarData, const QString& objectName);
void setAvatarHashMap(AvatarHashMap* avatarHashMap, const QString& objectName);
bool isListeningToAudioStream() const { return _isListeningToAudioStream; } bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
void setIsListeningToAudioStream(bool isListeningToAudioStream) { _isListeningToAudioStream = isListeningToAudioStream; } void setIsListeningToAudioStream(bool isListeningToAudioStream) { _isListeningToAudioStream = isListeningToAudioStream; }