243 lines · 10.8 KB · C++
RawDownload
////  Agent.cpp//  assignment-client/src////  Created by Stephen Birarda on 7/1/13.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <QtCore/QCoreApplication>#include <QtCore/QEventLoop>#include <QtCore/QStandardPaths>#include <QtCore/QTimer>#include <QtNetwork/QNetworkDiskCache>#include <QtNetwork/QNetworkRequest>#include <QtNetwork/QNetworkReply> #include <AudioRingBuffer.h>#include <AvatarData.h>#include <NetworkAccessManager.h>#include <NodeList.h>#include <PacketHeaders.h>#include <ResourceCache.h>#include <SoundCache.h>#include <UUID.h>#include <VoxelConstants.h> #include <EntityScriptingInterface.h> // TODO: consider moving to scriptengine.h #include "avatars/ScriptableAvatar.h" #include "Agent.h" static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; Agent::Agent(const QByteArray& packet) :    ThreadedAssignment(packet),    _voxelEditSender(),    _entityEditSender(),    _receivedAudioStream(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES,        InboundAudioStream::Settings(0, false, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, false,        DEFAULT_WINDOW_STARVE_THRESHOLD, DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES,        DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION, false)),    _avatarHashMap(){    // be the parent of the script engine so it gets moved when we do    _scriptEngine.setParent(this);        _scriptEngine.getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);    _scriptEngine.getEntityScriptingInterface()->setPacketSender(&_entityEditSender);} void Agent::readPendingDatagrams() {    QByteArray receivedPacket;    HifiSockAddr senderSockAddr;    NodeList* nodeList = NodeList::getInstance();        while (readAvailableDatagram(receivedPacket, senderSockAddr)) {        if (nodeList->packetVersionAndHashMatch(receivedPacket)) {            PacketType datagramPacketType = packetTypeForPacket(receivedPacket);                        if (datagramPacketType == PacketTypeJurisdiction) {                int headerBytes = numBytesForPacketHeader(receivedPacket);                                SharedNodePointer matchedNode = nodeList->sendingNodeForPacket(receivedPacket);                                if (matchedNode) {                    // PacketType_JURISDICTION, first byte is the node type...                    switch (receivedPacket[headerBytes]) {                        case NodeType::VoxelServer:                            _scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->                                                                queueReceivedPacket(matchedNode,receivedPacket);                            break;                            break;                        case NodeType::EntityServer:                            _scriptEngine.getEntityScriptingInterface()->getJurisdictionListener()->                                                                queueReceivedPacket(matchedNode, receivedPacket);                            break;                    }                }                            } else if (datagramPacketType == PacketTypeEntityAddResponse) {                // this will keep creatorTokenIDs to IDs mapped correctly                EntityItemID::handleAddEntityResponse(receivedPacket);                                // also give our local entity tree a chance to remap any internal locally created entities                _entityViewer.getTree()->handleAddEntityResponse(receivedPacket);                 // Make sure our Node and NodeList knows we've heard from this node.                SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);                sourceNode->setLastHeardMicrostamp(usecTimestampNow());             } else if (datagramPacketType == PacketTypeOctreeStats                        || datagramPacketType == PacketTypeVoxelData                        || datagramPacketType == PacketTypeEntityData                        || datagramPacketType == PacketTypeEntityErase            ) {                // Make sure our Node and NodeList knows we've heard from this node.                SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);                sourceNode->setLastHeardMicrostamp(usecTimestampNow());                 QByteArray mutablePacket = receivedPacket;                int messageLength = mutablePacket.size();                 if (datagramPacketType == PacketTypeOctreeStats) {                     int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(mutablePacket, sourceNode);                    if (messageLength > statsMessageLength) {                        mutablePacket = mutablePacket.mid(statsMessageLength);                                                // TODO: this needs to be fixed, the goal is to test the packet version for the piggyback, but                        //       this is testing the version and hash of the original packet                        //       need to use numBytesArithmeticCodingFromBuffer()...                        if (!NodeList::getInstance()->packetVersionAndHashMatch(receivedPacket)) {                            return; // bail since piggyback data doesn't match our versioning                        }                    } else {                        return; // bail since no piggyback data                    }                     datagramPacketType = packetTypeForPacket(mutablePacket);                } // fall through to piggyback message                 if (datagramPacketType == PacketTypeEntityData || datagramPacketType == PacketTypeEntityErase) {                    _entityViewer.processDatagram(mutablePacket, sourceNode);                }                                if (datagramPacketType == PacketTypeVoxelData) {                    _voxelViewer.processDatagram(mutablePacket, sourceNode);                }             } else if (datagramPacketType == PacketTypeMixedAudio || datagramPacketType == PacketTypeSilentAudioFrame) {                 _receivedAudioStream.parseData(receivedPacket);                 _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness();                 _receivedAudioStream.clearBuffer();                                // let this continue through to the NodeList so it updates last heard timestamp                // for the sending audio mixer                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 {                NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);            }        }    }} const QString AGENT_LOGGING_NAME = "agent"; void Agent::run() {    ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent);        NodeList* nodeList = NodeList::getInstance();    nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet()                                                 << NodeType::AudioMixer                                                 << NodeType::AvatarMixer                                                 << NodeType::VoxelServer                                                 << NodeType::EntityServer                                                );        // figure out the URL for the script for this agent assignment    QUrl scriptURL;    if (_payload.isEmpty())  {        scriptURL = QUrl(QString("http://%1:%2/assignment/%3")            .arg(NodeList::getInstance()->getDomainHandler().getIP().toString())            .arg(DOMAIN_SERVER_HTTP_PORT)            .arg(uuidStringWithoutCurlyBraces(_uuid)));    } else {        scriptURL = QUrl(_payload);    }       QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();    QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL));        QNetworkDiskCache* cache = new QNetworkDiskCache();    QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);    cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "agentCache");    networkAccessManager.setCache(cache);        qDebug() << "Downloading script at" << scriptURL.toString();        QEventLoop loop;    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));        loop.exec();        QString scriptContents(reply->readAll());        qDebug() << "Downloaded script:" << scriptContents;        // setup an Avatar for the script to use    ScriptableAvatar scriptedAvatar(&_scriptEngine);    scriptedAvatar.setForceFaceshiftConnected(true);     // call model URL setters with empty URLs so our avatar, if user, will have the default models    scriptedAvatar.setFaceModelURL(QUrl());    scriptedAvatar.setSkeletonModelURL(QUrl());        // give this AvatarData object to the script engine    _scriptEngine.setAvatarData(&scriptedAvatar, "Avatar");    _scriptEngine.setAvatarHashMap(&_avatarHashMap, "AvatarList");        // register ourselves to the script engine    _scriptEngine.registerGlobalObject("Agent", this);     _scriptEngine.init(); // must be done before we set up the viewers        _scriptEngine.registerGlobalObject("SoundCache", &SoundCache::getInstance());     _scriptEngine.registerGlobalObject("VoxelViewer", &_voxelViewer);    // connect the VoxelViewer and the VoxelScriptingInterface to each other    _voxelViewer.setJurisdictionListener(_scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener());    _voxelViewer.init();    _scriptEngine.getVoxelsScriptingInterface()->setVoxelTree(_voxelViewer.getTree());        _scriptEngine.registerGlobalObject("EntityViewer", &_entityViewer);    _entityViewer.setJurisdictionListener(_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener());    _entityViewer.init();    _scriptEngine.getEntityScriptingInterface()->setEntityTree(_entityViewer.getTree());     _scriptEngine.setScriptContents(scriptContents);    _scriptEngine.run();    setFinished(true);} void Agent::aboutToFinish() {    _scriptEngine.stop();    NetworkAccessManager::getInstance().clearAccessCache();}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t