mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 03:13:09 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into rationalize-rig-settings
This commit is contained in:
commit
02fba12a48
59 changed files with 713 additions and 739 deletions
|
@ -111,26 +111,29 @@ get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
|
|||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_CMAKE_PREFIX_PATH})
|
||||
|
||||
if (APPLE)
|
||||
|
||||
SET(OSX_SDK "10.9" CACHE String "OS X SDK version to look for inside Xcode bundle or at OSX_SDK_PATH")
|
||||
|
||||
# set our OS X deployment target
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.8)
|
||||
|
||||
# find the 10.9 SDK path
|
||||
# find the SDK path for the desired SDK
|
||||
find_path(
|
||||
_OSX_DESIRED_SDK_PATH
|
||||
NAME MacOSX10.9.sdk
|
||||
NAME MacOSX${OSX_SDK}.sdk
|
||||
HINTS ${OSX_SDK_PATH}
|
||||
PATHS /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
|
||||
/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
|
||||
)
|
||||
|
||||
if (NOT _OSX_DESIRED_SDK_PATH)
|
||||
message(FATAL_ERROR "Could not find OS X 10.9 SDK. Please pass OSX_SDK_PATH to CMake to point us to your SDKs directory.")
|
||||
message(FATAL_ERROR "Could not find OS X ${OSX_SDK} SDK. Please pass OSX_SDK_PATH to CMake to point us to your SDKs directory.")
|
||||
else ()
|
||||
message(STATUS "Found OS X 10.9 SDK at ${_OSX_DESIRED_SDK_PATH}/MacOSX10.9.sdk")
|
||||
message(STATUS "Found OS X ${OSX_SDK} SDK at ${_OSX_DESIRED_SDK_PATH}/MacOSX${OSX_SDK}.sdk")
|
||||
endif ()
|
||||
|
||||
# set that as the SDK to use
|
||||
set(CMAKE_OSX_SYSROOT ${_OSX_DESIRED_SDK_PATH}/MacOSX10.9.sdk)
|
||||
set(CMAKE_OSX_SYSROOT ${_OSX_DESIRED_SDK_PATH}/MacOSX${OSX_SDK}.sdk)
|
||||
endif ()
|
||||
|
||||
# Hide automoc folders (for IDEs)
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <signal.h>
|
||||
|
||||
#include <AddressManager.h>
|
||||
#include <JSONBreakableMarshal.h>
|
||||
#include <LogHandler.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
||||
|
@ -95,8 +94,10 @@ void AssignmentClientMonitor::stopChildProcesses() {
|
|||
|
||||
// ask child processes to terminate
|
||||
foreach(QProcess* childProcess, _childProcesses) {
|
||||
qDebug() << "Attempting to terminate child process" << childProcess->processId();
|
||||
childProcess->terminate();
|
||||
if (childProcess->processId() > 0) {
|
||||
qDebug() << "Attempting to terminate child process" << childProcess->processId();
|
||||
childProcess->terminate();
|
||||
}
|
||||
}
|
||||
|
||||
simultaneousWaitOnChildren(WAIT_FOR_CHILD_MSECS);
|
||||
|
@ -104,8 +105,10 @@ void AssignmentClientMonitor::stopChildProcesses() {
|
|||
if (_childProcesses.size() > 0) {
|
||||
// ask even more firmly
|
||||
foreach(QProcess* childProcess, _childProcesses) {
|
||||
qDebug() << "Attempting to kill child process" << childProcess->processId();
|
||||
childProcess->kill();
|
||||
if (childProcess->processId() > 0) {
|
||||
qDebug() << "Attempting to kill child process" << childProcess->processId();
|
||||
childProcess->kill();
|
||||
}
|
||||
}
|
||||
|
||||
simultaneousWaitOnChildren(WAIT_FOR_CHILD_MSECS);
|
||||
|
@ -155,12 +158,14 @@ void AssignmentClientMonitor::spawnChildClient() {
|
|||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||
|
||||
// make sure we hear that this process has finished when it does
|
||||
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(childProcessFinished()));
|
||||
|
||||
qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
|
||||
_childProcesses.insert(assignmentClient->processId(), assignmentClient);
|
||||
|
||||
if (assignmentClient->processId() > 0) {
|
||||
// make sure we hear that this process has finished when it does
|
||||
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(childProcessFinished()));
|
||||
|
||||
qDebug() << "Spawned a child client with PID" << assignmentClient->processId();
|
||||
_childProcesses.insert(assignmentClient->processId(), assignmentClient);
|
||||
}
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::checkSpares() {
|
||||
|
|
|
@ -12,14 +12,12 @@
|
|||
|
||||
#include "AssetServer.h"
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QCoreApplication>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QCoreApplication>
|
||||
#include <QEventLoop>
|
||||
#include <QRunnable>
|
||||
#include <QString>
|
||||
|
||||
#include "NetworkLogging.h"
|
||||
|
@ -165,3 +163,61 @@ void AssetServer::handleAssetUpload(QSharedPointer<NLPacketList> packetList, Sha
|
|||
}
|
||||
}
|
||||
|
||||
void AssetServer::sendStatsPacket() {
|
||||
QJsonObject serverStats;
|
||||
|
||||
auto stats = DependencyManager::get<NodeList>()->sampleStatsForAllConnections();
|
||||
|
||||
for (const auto& stat : stats) {
|
||||
QJsonObject nodeStats;
|
||||
auto endTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(stat.second.endTime);
|
||||
QDateTime date = QDateTime::fromMSecsSinceEpoch(endTimeMs.count());
|
||||
|
||||
QJsonObject connectionStats;
|
||||
connectionStats["lastHeard"] = date.toString();
|
||||
connectionStats["estimatedBandwith"] = stat.second.estimatedBandwith;
|
||||
connectionStats["rtt"] = stat.second.rtt;
|
||||
connectionStats["congestionWindowSize"] = stat.second.congestionWindowSize;
|
||||
connectionStats["packetSendPeriod"] = stat.second.packetSendPeriod;
|
||||
nodeStats["connection"] = connectionStats;
|
||||
|
||||
QJsonObject sendingStats;
|
||||
sendingStats["sendRate"] = stat.second.sendRate;
|
||||
sendingStats["sentPackets"] = stat.second.sentPackets;
|
||||
sendingStats["receivedACK"] = stat.second.events[udt::ConnectionStats::Stats::ReceivedACK];
|
||||
sendingStats["processedACK"] = stat.second.events[udt::ConnectionStats::Stats::ProcessedACK];
|
||||
sendingStats["receivedLightACK"] = stat.second.events[udt::ConnectionStats::Stats::ReceivedLightACK];
|
||||
sendingStats["receivedNAK"] = stat.second.events[udt::ConnectionStats::Stats::ReceivedNAK];
|
||||
sendingStats["receivedTimeoutNAK"] = stat.second.events[udt::ConnectionStats::Stats::ReceivedTimeoutNAK];
|
||||
sendingStats["sentACK2"] = stat.second.events[udt::ConnectionStats::Stats::SentACK2];
|
||||
sendingStats["retransmission"] = stat.second.events[udt::ConnectionStats::Stats::Retransmission];
|
||||
nodeStats["sending"] = sendingStats;
|
||||
|
||||
QJsonObject receivingStats;
|
||||
receivingStats["receiveRate"] = stat.second.receiveRate;
|
||||
receivingStats["receivedPackets"] = stat.second.receivedPackets;
|
||||
receivingStats["SentACK"] = stat.second.events[udt::ConnectionStats::Stats::SentACK];
|
||||
receivingStats["SentLightACK"] = stat.second.events[udt::ConnectionStats::Stats::SentLightACK];
|
||||
receivingStats["SentNAK"] = stat.second.events[udt::ConnectionStats::Stats::SentNAK];
|
||||
receivingStats["SentTimeoutNAK"] = stat.second.events[udt::ConnectionStats::Stats::SentTimeoutNAK];
|
||||
receivingStats["ReceivedACK2"] = stat.second.events[udt::ConnectionStats::Stats::ReceivedACK2];
|
||||
receivingStats["Duplicate"] = stat.second.events[udt::ConnectionStats::Stats::Duplicate];
|
||||
nodeStats["receiving"] = receivingStats;
|
||||
|
||||
QString uuid;
|
||||
auto nodelist = DependencyManager::get<NodeList>();
|
||||
if (stat.first == nodelist->getDomainHandler().getSockAddr()) {
|
||||
uuid = uuidStringWithoutCurlyBraces(nodelist->getDomainHandler().getUUID());
|
||||
nodeStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = "DomainServer";
|
||||
} else {
|
||||
auto node = nodelist->findNodeWithAddr(stat.first);
|
||||
uuid = uuidStringWithoutCurlyBraces(node ? node->getUUID() : QUuid());
|
||||
nodeStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = uuid;
|
||||
}
|
||||
|
||||
serverStats[uuid] = nodeStats;
|
||||
}
|
||||
|
||||
// send off the stats packets
|
||||
ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,9 @@ private slots:
|
|||
void handleAssetGetInfo(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
void handleAssetGet(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
void handleAssetUpload(QSharedPointer<NLPacketList> packetList, SharedNodePointer senderNode);
|
||||
|
||||
|
||||
void sendStatsPacket();
|
||||
|
||||
private:
|
||||
static void writeError(NLPacketList* packetList, AssetServerError error);
|
||||
QDir _resourcesDirectory;
|
||||
|
|
|
@ -52,7 +52,7 @@ void SendAssetTask::run() {
|
|||
qDebug() << "Received a request for the file (" << messageID << "): " << hexHash << " from " << start << " to " << end;
|
||||
|
||||
qDebug() << "Starting task to send asset: " << hexHash << " for messageID " << messageID;
|
||||
auto replyPacketList = std::unique_ptr<NLPacketList>(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true));
|
||||
auto replyPacketList = NLPacketList::create(PacketType::AssetGetReply, QByteArray(), true, true);
|
||||
|
||||
replyPacketList->write(assetHash);
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
}
|
||||
|
||||
// setup a PacketList for the avatarPackets
|
||||
NLPacketList avatarPacketList(PacketType::BulkAvatarData);
|
||||
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
||||
|
||||
// this is an AGENT we have received head data from
|
||||
// send back a packet with other active node data to this node
|
||||
|
@ -292,13 +292,13 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
otherNodeData->getLastReceivedSequenceNumber());
|
||||
|
||||
// start a new segment in the PacketList for this avatar
|
||||
avatarPacketList.startSegment();
|
||||
avatarPacketList->startSegment();
|
||||
|
||||
numAvatarDataBytes += avatarPacketList.write(otherNode->getUUID().toRfc4122());
|
||||
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
||||
numAvatarDataBytes +=
|
||||
avatarPacketList.write(otherAvatar.toByteArray(false, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO));
|
||||
avatarPacketList->write(otherAvatar.toByteArray(false, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO));
|
||||
|
||||
avatarPacketList.endSegment();
|
||||
avatarPacketList->endSegment();
|
||||
|
||||
// if the receiving avatar has just connected make sure we send out the mesh and billboard
|
||||
// for this avatar (assuming they exist)
|
||||
|
@ -344,10 +344,10 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
});
|
||||
|
||||
// close the current packet so that we're always sending something
|
||||
avatarPacketList.closeCurrentPacket(true);
|
||||
avatarPacketList->closeCurrentPacket(true);
|
||||
|
||||
// send the avatar data PacketList
|
||||
nodeList->sendPacketList(avatarPacketList, *node);
|
||||
nodeList->sendPacketList(std::move(avatarPacketList), *node);
|
||||
|
||||
// record the bytes sent for other avatar data in the AvatarMixerClientData
|
||||
nodeData->recordSentAvatarData(numAvatarDataBytes);
|
||||
|
|
|
@ -238,7 +238,7 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
NLPacketList nackPacketList(_myServer->getMyEditNackType());
|
||||
auto nackPacketList = NLPacketList::create(_myServer->getMyEditNackType());
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
int packetsSent = 0;
|
||||
|
||||
|
@ -274,18 +274,18 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
|
|||
|
||||
while (it != missingSequenceNumbers.constEnd()) {
|
||||
unsigned short int sequenceNumber = *it;
|
||||
nackPacketList.writePrimitive(sequenceNumber);
|
||||
nackPacketList->writePrimitive(sequenceNumber);
|
||||
++it;
|
||||
}
|
||||
|
||||
|
||||
if (nackPacketList.getNumPackets()) {
|
||||
if (nackPacketList->getNumPackets()) {
|
||||
qDebug() << "NACK Sent back to editor/client... destinationNode=" << nodeUUID;
|
||||
|
||||
packetsSent += nackPacketList.getNumPackets();
|
||||
packetsSent += nackPacketList->getNumPackets();
|
||||
|
||||
// send the list of nack packets
|
||||
nodeList->sendPacketList(nackPacketList, *destinationNode);
|
||||
nodeList->sendPacketList(std::move(nackPacketList), *destinationNode);
|
||||
}
|
||||
|
||||
++i;
|
||||
|
|
|
@ -1293,81 +1293,85 @@ QString OctreeServer::getStatusLink() {
|
|||
}
|
||||
|
||||
void OctreeServer::sendStatsPacket() {
|
||||
// TODO: we have too many stats to fit in a single MTU... so for now, we break it into multiple JSON objects and
|
||||
// send them separately. What we really should do is change the NodeList::sendStatsToDomainServer() to handle the
|
||||
// the following features:
|
||||
// 1) remember last state sent
|
||||
// 2) only send new data
|
||||
// 3) automatically break up into multiple packets
|
||||
static QJsonObject statsObject1;
|
||||
|
||||
QString baseName = getMyServerName() + QString("Server");
|
||||
|
||||
statsObject1[baseName + QString(".0.1.configuration")] = getConfiguration();
|
||||
|
||||
statsObject1[baseName + QString(".0.2.detailed_stats_url")] = getStatusLink();
|
||||
|
||||
statsObject1[baseName + QString(".0.3.uptime")] = getUptime();
|
||||
statsObject1[baseName + QString(".0.4.persistFileLoadTime")] = getFileLoadTime();
|
||||
statsObject1[baseName + QString(".0.5.clients")] = getCurrentClientCount();
|
||||
|
||||
// Stats Array 1
|
||||
QJsonArray threadsStats;
|
||||
quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND;
|
||||
threadsStats.push_back(QJsonObject({{"processing", (double)howManyThreadsDidProcess(oneSecondAgo)}}));
|
||||
threadsStats.push_back(QJsonObject({{"packetDistributor", (double)howManyThreadsDidPacketDistributor(oneSecondAgo)}}));
|
||||
threadsStats.push_back(QJsonObject({{"handlePacektSend", (double)howManyThreadsDidHandlePacketSend(oneSecondAgo)}}));
|
||||
threadsStats.push_back(QJsonObject({{"writeDatagram", (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo)}}));
|
||||
|
||||
QJsonArray statsArray1;
|
||||
statsArray1.push_back(QJsonObject({{"configuration", getConfiguration()}}));
|
||||
statsArray1.push_back(QJsonObject({{"detailed_stats_url", getStatusLink()}}));
|
||||
statsArray1.push_back(QJsonObject({{"uptime", getUptime()}}));
|
||||
statsArray1.push_back(QJsonObject({{"persistFileLoadTime", getFileLoadTime()}}));
|
||||
statsArray1.push_back(QJsonObject({{"clients", getCurrentClientCount()}}));
|
||||
statsArray1.push_back(QJsonObject({{"threads", threadsStats}}));
|
||||
|
||||
// Octree Stats
|
||||
QJsonArray octreeStats;
|
||||
octreeStats.push_back(QJsonObject({{"elementCount", (double)OctreeElement::getNodeCount()}}));
|
||||
octreeStats.push_back(QJsonObject({{"internalElementCount", (double)OctreeElement::getInternalNodeCount()}}));
|
||||
octreeStats.push_back(QJsonObject({{"leafElementCount", (double)OctreeElement::getLeafNodeCount()}}));
|
||||
|
||||
// Stats Object 2
|
||||
QJsonObject dataObject1;
|
||||
dataObject1["totalPackets"] = (double)OctreeSendThread::_totalPackets;
|
||||
dataObject1["totalBytes"] = (double)OctreeSendThread::_totalBytes;
|
||||
dataObject1["totalBytesWasted"] = (double)OctreeSendThread::_totalWastedBytes;
|
||||
dataObject1["totalBytesOctalCodes"] = (double)OctreePacketData::getTotalBytesOfOctalCodes();
|
||||
dataObject1["totalBytesBitMasks"] = (double)OctreePacketData::getTotalBytesOfBitMasks();
|
||||
dataObject1["totalBytesBitMasks"] = (double)OctreePacketData::getTotalBytesOfColor();
|
||||
|
||||
statsObject1[baseName + QString(".0.6.threads.1.processing")] = (double)howManyThreadsDidProcess(oneSecondAgo);
|
||||
statsObject1[baseName + QString(".0.6.threads.2.packetDistributor")] =
|
||||
(double)howManyThreadsDidPacketDistributor(oneSecondAgo);
|
||||
statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] =
|
||||
(double)howManyThreadsDidHandlePacketSend(oneSecondAgo);
|
||||
statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] =
|
||||
(double)howManyThreadsDidCallWriteDatagram(oneSecondAgo);
|
||||
|
||||
statsObject1[baseName + QString(".1.1.octree.elementCount")] = (double)OctreeElement::getNodeCount();
|
||||
statsObject1[baseName + QString(".1.2.octree.internalElementCount")] = (double)OctreeElement::getInternalNodeCount();
|
||||
statsObject1[baseName + QString(".1.3.octree.leafElementCount")] = (double)OctreeElement::getLeafNodeCount();
|
||||
|
||||
ThreadedAssignment::addPacketStatsAndSendStatsPacket(statsObject1);
|
||||
|
||||
static QJsonObject statsObject2;
|
||||
|
||||
statsObject2[baseName + QString(".2.outbound.data.totalPackets")] = (double)OctreeSendThread::_totalPackets;
|
||||
statsObject2[baseName + QString(".2.outbound.data.totalBytes")] = (double)OctreeSendThread::_totalBytes;
|
||||
statsObject2[baseName + QString(".2.outbound.data.totalBytesWasted")] = (double)OctreeSendThread::_totalWastedBytes;
|
||||
statsObject2[baseName + QString(".2.outbound.data.totalBytesOctalCodes")] =
|
||||
(double)OctreePacketData::getTotalBytesOfOctalCodes();
|
||||
statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] =
|
||||
(double)OctreePacketData::getTotalBytesOfBitMasks();
|
||||
statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = (double)OctreePacketData::getTotalBytesOfColor();
|
||||
|
||||
statsObject2[baseName + QString(".2.outbound.timing.1.avgLoopTime")] = getAverageLoopTime();
|
||||
statsObject2[baseName + QString(".2.outbound.timing.2.avgInsideTime")] = getAverageInsideTime();
|
||||
statsObject2[baseName + QString(".2.outbound.timing.3.avgTreeLockTime")] = getAverageTreeWaitTime();
|
||||
statsObject2[baseName + QString(".2.outbound.timing.4.avgEncodeTime")] = getAverageEncodeTime();
|
||||
statsObject2[baseName + QString(".2.outbound.timing.5.avgCompressAndWriteTime")] = getAverageCompressAndWriteTime();
|
||||
statsObject2[baseName + QString(".2.outbound.timing.5.avgSendTime")] = getAveragePacketSendingTime();
|
||||
statsObject2[baseName + QString(".2.outbound.timing.5.nodeWaitTime")] = getAverageNodeWaitTime();
|
||||
|
||||
DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject2);
|
||||
|
||||
static QJsonObject statsObject3;
|
||||
|
||||
statsObject3[baseName + QString(".3.inbound.data.1.packetQueue")] =
|
||||
(double)_octreeInboundPacketProcessor->packetsToProcessCount();
|
||||
statsObject3[baseName + QString(".3.inbound.data.1.totalPackets")] =
|
||||
(double)_octreeInboundPacketProcessor->getTotalPacketsProcessed();
|
||||
statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] =
|
||||
(double)_octreeInboundPacketProcessor->getTotalElementsProcessed();
|
||||
statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] =
|
||||
(double)_octreeInboundPacketProcessor->getAverageTransitTimePerPacket();
|
||||
statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] =
|
||||
(double)_octreeInboundPacketProcessor->getAverageProcessTimePerPacket();
|
||||
statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] =
|
||||
(double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket();
|
||||
statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] =
|
||||
(double)_octreeInboundPacketProcessor->getAverageProcessTimePerElement();
|
||||
statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] =
|
||||
(double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement();
|
||||
|
||||
DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3);
|
||||
QJsonArray timingArray1;
|
||||
timingArray1.push_back(QJsonObject({{"avgLoopTime", getAverageLoopTime()}}));
|
||||
timingArray1.push_back(QJsonObject({{"avgInsideTime", getAverageInsideTime()}}));
|
||||
timingArray1.push_back(QJsonObject({{"avgTreeLockTime", getAverageTreeWaitTime()}}));
|
||||
timingArray1.push_back(QJsonObject({{"avgEncodeTime", getAverageEncodeTime()}}));
|
||||
timingArray1.push_back(QJsonObject({{"avgCompressAndWriteTime", getAverageCompressAndWriteTime()}}));
|
||||
timingArray1.push_back(QJsonObject({{"avgSendTime", getAveragePacketSendingTime()}}));
|
||||
timingArray1.push_back(QJsonObject({{"nodeWaitTime", getAverageNodeWaitTime()}}));
|
||||
|
||||
QJsonObject statsObject2;
|
||||
statsObject2["data"] = dataObject1;
|
||||
statsObject2["timing"] = timingArray1;
|
||||
|
||||
// Stats Object 3
|
||||
QJsonArray dataArray2;
|
||||
dataArray2.push_back(QJsonObject({{"packetQueue",
|
||||
(double)_octreeInboundPacketProcessor->packetsToProcessCount()}}));
|
||||
dataArray2.push_back(QJsonObject({{"totalPackets",
|
||||
(double)_octreeInboundPacketProcessor->getTotalPacketsProcessed()}}));
|
||||
dataArray2.push_back(QJsonObject({{"totalElements",
|
||||
(double)_octreeInboundPacketProcessor->getTotalElementsProcessed()}}));
|
||||
|
||||
QJsonArray timingArray2;
|
||||
timingArray2.push_back(QJsonObject({{"avgTransitTimePerPacket",
|
||||
(double)_octreeInboundPacketProcessor->getAverageTransitTimePerPacket()}}));
|
||||
timingArray2.push_back(QJsonObject({{"avgProcessTimePerPacket",
|
||||
(double)_octreeInboundPacketProcessor->getAverageProcessTimePerPacket()}}));
|
||||
timingArray2.push_back(QJsonObject({{"avgLockWaitTimePerPacket",
|
||||
(double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket()}}));
|
||||
timingArray2.push_back(QJsonObject({{"avgProcessTimePerElement",
|
||||
(double)_octreeInboundPacketProcessor->getAverageProcessTimePerElement()}}));
|
||||
timingArray2.push_back(QJsonObject({{"avgLockWaitTimePerElement",
|
||||
(double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement()}}));
|
||||
|
||||
QJsonObject statsObject3;
|
||||
statsObject3["data"] = dataArray2;
|
||||
statsObject3["timing"] = timingArray2;
|
||||
|
||||
// Merge everything
|
||||
QJsonArray jsonArray;
|
||||
jsonArray.push_back(statsArray1);
|
||||
jsonArray.push_back(QJsonObject({{"octree", octreeStats}}));
|
||||
jsonArray.push_back(QJsonObject({{"outbound", statsObject2}}));
|
||||
jsonArray.push_back(QJsonObject({{"inbound", statsObject3}}));
|
||||
|
||||
QJsonObject statsObject;
|
||||
statsObject[QString(getMyServerName()) + "Server"] = jsonArray;
|
||||
addPacketStatsAndSendStatsPacket(statsObject);
|
||||
}
|
||||
|
||||
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidProcess;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include <AccountManager.h>
|
||||
#include <Assignment.h>
|
||||
#include <JSONBreakableMarshal.h>
|
||||
|
||||
#include "DomainServer.h"
|
||||
#include "DomainServerNodeData.h"
|
||||
|
@ -272,9 +271,9 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
|||
// if we have a username from the connect request, set it on the DomainServerNodeData
|
||||
nodeData->setUsername(username);
|
||||
|
||||
// also add an interpolation to JSONBreakableMarshal so that servers can get username in stats
|
||||
JSONBreakableMarshal::addInterpolationForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
|
||||
uuidStringWithoutCurlyBraces(newNode->getUUID()), username);
|
||||
// also add an interpolation to DomainServerNodeData so that servers can get username in stats
|
||||
nodeData->addOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
|
||||
uuidStringWithoutCurlyBraces(newNode->getUUID()), username);
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <ApplicationVersion.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <HTTPConnection.h>
|
||||
#include <JSONBreakableMarshal.h>
|
||||
#include <LogUtils.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
@ -287,7 +286,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
packetReceiver.registerListener(PacketType::RequestAssignment, this, "processRequestAssignmentPacket");
|
||||
packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket");
|
||||
packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket");
|
||||
packetReceiver.registerListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket");
|
||||
packetReceiver.registerMessageListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket");
|
||||
|
||||
// NodeList won't be available to the settings manager when it is created, so call registerListener here
|
||||
packetReceiver.registerListener(PacketType::DomainSettingsRequest, &_settingsManager, "processSettingsRequestPacket");
|
||||
|
@ -679,10 +678,10 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
extendedHeaderStream << (quint8) node->getCanAdjustLocks();
|
||||
extendedHeaderStream << (quint8) node->getCanRez();
|
||||
|
||||
NLPacketList domainListPackets(PacketType::DomainList, extendedHeader);
|
||||
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
||||
|
||||
// always send the node their own UUID back
|
||||
QDataStream domainListStream(&domainListPackets);
|
||||
QDataStream domainListStream(domainListPackets.get());
|
||||
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
|
||||
|
@ -698,7 +697,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
if (otherNode->getUUID() != node->getUUID() && nodeInterestSet.contains(otherNode->getType())) {
|
||||
|
||||
// since we're about to add a node to the packet we start a segment
|
||||
domainListPackets.startSegment();
|
||||
domainListPackets->startSegment();
|
||||
|
||||
// don't send avatar nodes to other avatars, that will come from avatar mixer
|
||||
domainListStream << *otherNode.data();
|
||||
|
@ -707,17 +706,17 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
domainListStream << connectionSecretForNodes(node, otherNode);
|
||||
|
||||
// we've added the node we wanted so end the segment now
|
||||
domainListPackets.endSegment();
|
||||
domainListPackets->endSegment();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// send an empty list to the node, in case there were no other nodes
|
||||
domainListPackets.closeCurrentPacket(true);
|
||||
domainListPackets->closeCurrentPacket(true);
|
||||
|
||||
// write the PacketList to this node
|
||||
limitedNodeList->sendPacketList(domainListPackets, *node);
|
||||
limitedNodeList->sendPacketList(std::move(domainListPackets), *node);
|
||||
}
|
||||
|
||||
QUuid DomainServer::connectionSecretForNodes(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB) {
|
||||
|
@ -1007,10 +1006,10 @@ void DomainServer::sendHeartbeatToIceServer() {
|
|||
DependencyManager::get<LimitedNodeList>()->sendHeartbeatToIceServer(_iceServerSocket);
|
||||
}
|
||||
|
||||
void DomainServer::processNodeJSONStatsPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
void DomainServer::processNodeJSONStatsPacket(QSharedPointer<NLPacketList> packetList, SharedNodePointer sendingNode) {
|
||||
auto nodeData = dynamic_cast<DomainServerNodeData*>(sendingNode->getLinkedData());
|
||||
if (nodeData) {
|
||||
nodeData->processJSONStatsPacket(*packet);
|
||||
nodeData->updateJSONStats(packetList->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1676,9 +1675,9 @@ void DomainServer::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
}
|
||||
|
||||
// If this node was an Agent ask JSONBreakableMarshal to potentially remove the interpolation we stored
|
||||
JSONBreakableMarshal::removeInterpolationForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
|
||||
uuidStringWithoutCurlyBraces(node->getUUID()));
|
||||
// If this node was an Agent ask DomainServerNodeData to potentially remove the interpolation we stored
|
||||
nodeData->removeOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
|
||||
uuidStringWithoutCurlyBraces(node->getUUID()));
|
||||
|
||||
// cleanup the connection secrets that we set up for this node (on the other nodes)
|
||||
foreach (const QUuid& otherNodeSessionUUID, nodeData->getSessionSecretHash().keys()) {
|
||||
|
|
|
@ -58,7 +58,7 @@ public slots:
|
|||
|
||||
void processRequestAssignmentPacket(QSharedPointer<NLPacket> packet);
|
||||
void processListRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void processNodeJSONStatsPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void processNodeJSONStatsPacket(QSharedPointer<NLPacketList> packetList, SharedNodePointer sendingNode);
|
||||
void processPathQueryPacket(QSharedPointer<NLPacket> packet);
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -10,40 +10,69 @@
|
|||
//
|
||||
|
||||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
#include <JSONBreakableMarshal.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
||||
#include "DomainServerNodeData.h"
|
||||
|
||||
DomainServerNodeData::DomainServerNodeData() :
|
||||
_sessionSecretHash(),
|
||||
_assignmentUUID(),
|
||||
_walletUUID(),
|
||||
_username(),
|
||||
_paymentIntervalTimer(),
|
||||
_statsJSONObject(),
|
||||
_sendingSockAddr(),
|
||||
_isAuthenticated(true)
|
||||
{
|
||||
DomainServerNodeData::StringPairHash DomainServerNodeData::_overrideHash;
|
||||
|
||||
DomainServerNodeData::DomainServerNodeData() {
|
||||
_paymentIntervalTimer.start();
|
||||
}
|
||||
|
||||
void DomainServerNodeData::processJSONStatsPacket(NLPacket& statsPacket) {
|
||||
QVariantMap packetVariantMap = JSONBreakableMarshal::fromStringBuffer(statsPacket.readAll());
|
||||
_statsJSONObject = mergeJSONStatsFromNewObject(QJsonObject::fromVariantMap(packetVariantMap), _statsJSONObject);
|
||||
void DomainServerNodeData::updateJSONStats(QByteArray statsByteArray) {
|
||||
auto document = QJsonDocument::fromBinaryData(statsByteArray);
|
||||
Q_ASSERT(document.isObject());
|
||||
_statsJSONObject = overrideValuesIfNeeded(document.object());
|
||||
}
|
||||
|
||||
QJsonObject DomainServerNodeData::mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject) {
|
||||
foreach(const QString& key, newObject.keys()) {
|
||||
if (newObject[key].isObject() && destinationObject.contains(key)) {
|
||||
destinationObject[key] = mergeJSONStatsFromNewObject(newObject[key].toObject(), destinationObject[key].toObject());
|
||||
QJsonObject DomainServerNodeData::overrideValuesIfNeeded(const QJsonObject& newStats) {
|
||||
QJsonObject result;
|
||||
for (auto it = newStats.constBegin(); it != newStats.constEnd(); ++it) {
|
||||
const auto& key = it.key();
|
||||
const auto& value = it.value();
|
||||
|
||||
auto overrideIt = value.isString() ? _overrideHash.find({key, value.toString()}) : _overrideHash.end();
|
||||
if (overrideIt != _overrideHash.end()) {
|
||||
// We have a match, override the value
|
||||
result[key] = *overrideIt;
|
||||
} else if (value.isObject()) {
|
||||
result[key] = overrideValuesIfNeeded(value.toObject());
|
||||
} else if (value.isArray()) {
|
||||
result[key] = overrideValuesIfNeeded(value.toArray());
|
||||
} else {
|
||||
destinationObject[key] = newObject[key];
|
||||
result[key] = newStats[key];
|
||||
}
|
||||
}
|
||||
|
||||
return destinationObject;
|
||||
return result;
|
||||
}
|
||||
|
||||
QJsonArray DomainServerNodeData::overrideValuesIfNeeded(const QJsonArray& newStats) {
|
||||
QJsonArray result;
|
||||
for (const auto& value : newStats) {
|
||||
if (value.isObject()) {
|
||||
result.push_back(overrideValuesIfNeeded(value.toObject()));
|
||||
} else if (value.isArray()) {
|
||||
result.push_back(overrideValuesIfNeeded(value.toArray()));
|
||||
} else {
|
||||
result.push_back(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void DomainServerNodeData::addOverrideForKey(const QString& key, const QString& value,
|
||||
const QString& overrideValue) {
|
||||
// Insert override value
|
||||
_overrideHash.insert({key, value}, overrideValue);
|
||||
}
|
||||
|
||||
void DomainServerNodeData::removeOverrideForKey(const QString& key, const QString& value) {
|
||||
// Remove override value
|
||||
_overrideHash.remove({key, value});
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
|
||||
const QJsonObject& getStatsJSONObject() const { return _statsJSONObject; }
|
||||
|
||||
void processJSONStatsPacket(NLPacket& packet);
|
||||
void updateJSONStats(QByteArray statsByteArray);
|
||||
|
||||
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
|
||||
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
|
||||
|
@ -54,17 +54,25 @@ public:
|
|||
void setNodeVersion(const QString& nodeVersion) { _nodeVersion = nodeVersion; }
|
||||
const QString& getNodeVersion() { return _nodeVersion; }
|
||||
|
||||
void addOverrideForKey(const QString& key, const QString& value, const QString& overrideValue);
|
||||
void removeOverrideForKey(const QString& key, const QString& value);
|
||||
|
||||
private:
|
||||
QJsonObject mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject);
|
||||
|
||||
QJsonObject overrideValuesIfNeeded(const QJsonObject& newStats);
|
||||
QJsonArray overrideValuesIfNeeded(const QJsonArray& newStats);
|
||||
|
||||
QHash<QUuid, QUuid> _sessionSecretHash;
|
||||
QUuid _assignmentUUID;
|
||||
QUuid _walletUUID;
|
||||
QString _username;
|
||||
QElapsedTimer _paymentIntervalTimer;
|
||||
|
||||
using StringPairHash = QHash<QPair<QString, QString>, QString>;
|
||||
QJsonObject _statsJSONObject;
|
||||
static StringPairHash _overrideHash;
|
||||
|
||||
HifiSockAddr _sendingSockAddr;
|
||||
bool _isAuthenticated;
|
||||
bool _isAuthenticated = true;
|
||||
NodeSet _nodeInterestSet;
|
||||
QString _nodeVersion;
|
||||
};
|
||||
|
|
|
@ -74,7 +74,7 @@ void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer<NL
|
|||
QJsonObject responseObject = responseObjectForType(QString::number(type));
|
||||
auto json = QJsonDocument(responseObject).toJson();
|
||||
|
||||
auto packetList = std::unique_ptr<NLPacketList>(new NLPacketList(PacketType::DomainSettings, QByteArray(), true, true));
|
||||
auto packetList = NLPacketList::create(PacketType::DomainSettings, QByteArray(), true, true);
|
||||
|
||||
packetList->write(json);
|
||||
|
||||
|
|
|
@ -260,6 +260,7 @@ var toolBar = (function () {
|
|||
cameraManager.disable();
|
||||
} else {
|
||||
hasShownPropertiesTool = false;
|
||||
cameraManager.enable();
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
grid.setEnabled(true);
|
||||
|
@ -669,11 +670,15 @@ function mouseMove(event) {
|
|||
|
||||
lastMousePosition = { x: event.x, y: event.y };
|
||||
|
||||
highlightEntityUnderCursor(lastMousePosition, false);
|
||||
idleMouseTimerId = Script.setTimeout(handleIdleMouse, IDLE_MOUSE_TIMEOUT);
|
||||
}
|
||||
|
||||
function handleIdleMouse() {
|
||||
idleMouseTimerId = null;
|
||||
if (isActive) {
|
||||
highlightEntityUnderCursor(lastMousePosition, true);
|
||||
}
|
||||
}
|
||||
|
||||
function highlightEntityUnderCursor(position, accurateRay) {
|
||||
|
@ -797,7 +802,6 @@ function mouseClickEvent(event) {
|
|||
selectionDisplay.select(selectedEntityID, event);
|
||||
|
||||
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
|
||||
cameraManager.enable();
|
||||
cameraManager.focus(selectionManager.worldPosition,
|
||||
selectionManager.worldDimensions,
|
||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
|
@ -1138,7 +1142,6 @@ Controller.keyReleaseEvent.connect(function (event) {
|
|||
} else if (event.text == "f") {
|
||||
if (isActive) {
|
||||
if (selectionManager.hasSelection()) {
|
||||
cameraManager.enable();
|
||||
cameraManager.focus(selectionManager.worldPosition,
|
||||
selectionManager.worldDimensions,
|
||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
|
|
|
@ -49,7 +49,7 @@ EntityListTool = function(opts) {
|
|||
|
||||
var selectedIDs = [];
|
||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||
selectedIDs.push(selectionManager.selections[i].id);
|
||||
selectedIDs.push(selectionManager.selections[i].id); // ?
|
||||
}
|
||||
|
||||
var data = {
|
||||
|
@ -70,7 +70,6 @@ EntityListTool = function(opts) {
|
|||
}
|
||||
selectionManager.setSelections(entityIDs);
|
||||
if (data.focus) {
|
||||
cameraManager.enable();
|
||||
cameraManager.focus(selectionManager.worldPosition,
|
||||
selectionManager.worldDimensions,
|
||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
(function() {
|
||||
|
||||
function debugPrint(message) {
|
||||
// print(message);
|
||||
//print(message);
|
||||
}
|
||||
|
||||
Script.include("../../libraries/utils.js");
|
||||
|
@ -31,6 +31,15 @@
|
|||
_this._spotlight = null;
|
||||
};
|
||||
|
||||
|
||||
GRAB_FRAME_USER_DATA_KEY = "grabFrame";
|
||||
|
||||
// These constants define the Flashlight model Grab Frame
|
||||
var MODEL_GRAB_FRAME = {
|
||||
relativePosition: {x: 0, y: -0.1, z: 0},
|
||||
relativeRotation: Quat.angleAxis(180, {x: 1, y: 0, z: 0})
|
||||
};
|
||||
|
||||
// These constants define the Spotlight position and orientation relative to the model
|
||||
var MODEL_LIGHT_POSITION = {x: 0, y: 0, z: 0};
|
||||
var MODEL_LIGHT_ROTATION = Quat.angleAxis (-90, {x: 1, y: 0, z: 0});
|
||||
|
@ -43,6 +52,8 @@
|
|||
|
||||
Flashlight.prototype = {
|
||||
|
||||
|
||||
|
||||
// update() will be called regulary, because we've hooked the update signal in our preload() function
|
||||
// we will check out userData for the grabData. In the case of the hydraGrab script, it will tell us
|
||||
// if we're currently being grabbed and if the person grabbing us is the current interfaces avatar.
|
||||
|
@ -126,11 +137,20 @@
|
|||
// * connecting to the update signal so we can check our grabbed state
|
||||
preload: function(entityID) {
|
||||
_this.entityID = entityID;
|
||||
|
||||
|
||||
var modelProperties = Entities.getEntityProperties(entityID);
|
||||
_this._startModelPosition = modelProperties.position;
|
||||
_this._startModelRotation = modelProperties.rotation;
|
||||
|
||||
// Make sure the Flashlight entity has a correct grab frame setup
|
||||
var userData = getEntityUserData(entityID);
|
||||
debugPrint(JSON.stringify(userData));
|
||||
if (!userData.grabFrame) {
|
||||
setEntityCustomData(GRAB_FRAME_USER_DATA_KEY, entityID, MODEL_GRAB_FRAME);
|
||||
debugPrint(JSON.stringify(MODEL_GRAB_FRAME));
|
||||
debugPrint("Assigned the grab frmae for the Flashlight entity");
|
||||
}
|
||||
|
||||
Script.update.connect(this.update);
|
||||
},
|
||||
|
||||
|
|
|
@ -142,6 +142,7 @@
|
|||
#include "SpeechRecognizer.h"
|
||||
#endif
|
||||
|
||||
#include "ui/AddressBarDialog.h"
|
||||
#include "ui/AvatarInputs.h"
|
||||
#include "ui/DataWebDialog.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
|
@ -149,7 +150,6 @@
|
|||
#include "ui/Snapshot.h"
|
||||
#include "ui/StandAloneJSConsole.h"
|
||||
#include "ui/Stats.h"
|
||||
#include "ui/AddressBarDialog.h"
|
||||
#include "ui/UpdateDialog.h"
|
||||
#include "ui/overlays/Cube3DOverlay.h"
|
||||
|
||||
|
@ -3033,7 +3033,7 @@ int Application::sendNackPackets() {
|
|||
|
||||
if (node->getActiveSocket() && node->getType() == NodeType::EntityServer) {
|
||||
|
||||
NLPacketList nackPacketList(PacketType::OctreeDataNack);
|
||||
auto nackPacketList = NLPacketList::create(PacketType::OctreeDataNack);
|
||||
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
|
||||
|
@ -3062,15 +3062,15 @@ int Application::sendNackPackets() {
|
|||
auto it = missingSequenceNumbers.constBegin();
|
||||
while (it != missingSequenceNumbers.constEnd()) {
|
||||
OCTREE_PACKET_SEQUENCE missingNumber = *it;
|
||||
nackPacketList.writePrimitive(missingNumber);
|
||||
nackPacketList->writePrimitive(missingNumber);
|
||||
++it;
|
||||
}
|
||||
|
||||
if (nackPacketList.getNumPackets()) {
|
||||
packetsSent += nackPacketList.getNumPackets();
|
||||
if (nackPacketList->getNumPackets()) {
|
||||
packetsSent += nackPacketList->getNumPackets();
|
||||
|
||||
// send the packet list
|
||||
nodeList->sendPacketList(nackPacketList, *node);
|
||||
nodeList->sendPacketList(std::move(nackPacketList), *node);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1295,7 +1295,8 @@ void MyAvatar::initAnimGraph() {
|
|||
//
|
||||
// or run a local web-server
|
||||
// python -m SimpleHTTPServer&
|
||||
auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/e58e0a24cc341ad5d060/raw/2a994bef7726ce8e9efcee7622b8b1a1b6b67490/ik-avatar.json");
|
||||
// auto graphUrl = QUrl("http://localhost:8000/avatar.json");
|
||||
auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/e58e0a24cc341ad5d060/raw/8f824da2908fd89ad1befadd1d8f5d7b3b6efa66/ik-avatar.json");
|
||||
_rig->initAnimGraph(graphUrl, _skeletonModel.getGeometry()->getFBXGeometry());
|
||||
}
|
||||
|
||||
|
|
|
@ -116,6 +116,17 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
params.leanForward = head->getFinalLeanForward();
|
||||
params.torsoTwist = head->getTorsoTwist();
|
||||
params.localHeadOrientation = head->getFinalOrientationInLocalFrame();
|
||||
params.localHeadPitch = head->getFinalPitch();
|
||||
params.localHeadYaw = head->getFinalYaw();
|
||||
params.localHeadRoll = head->getFinalRoll();
|
||||
params.isInHMD = qApp->getAvatarUpdater()->isHMDMode();
|
||||
|
||||
// get HMD position from sensor space into world space, and back into model space
|
||||
glm::mat4 worldToModel = glm::inverse(createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()));
|
||||
glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 hmdPosition = glm::angleAxis((float)M_PI, yAxis) * transformPoint(worldToModel * myAvatar->getSensorToWorldMatrix(), myAvatar->getHMDSensorPosition());
|
||||
params.localHeadPosition = hmdPosition;
|
||||
|
||||
params.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
|
||||
params.eyeLookAt = head->getLookAtPosition();
|
||||
params.eyeSaccade = head->getSaccade();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//
|
||||
// AddressBarDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//
|
||||
// AddressBarDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
|
|
|
@ -69,7 +69,7 @@ void AssetUploadDialogFactory::showDialog() {
|
|||
}
|
||||
|
||||
void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const QString& hash) {
|
||||
if (upload->getResult() == AssetUpload::Success) {
|
||||
if (upload->getError() == AssetUpload::NoError) {
|
||||
// show message box for successful upload, with copiable text for ATP hash
|
||||
QDialog* hashCopyDialog = new QDialog(_dialogParent);
|
||||
|
||||
|
@ -124,14 +124,14 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q
|
|||
// figure out the right error message for the message box
|
||||
QString additionalError;
|
||||
|
||||
switch (upload->getResult()) {
|
||||
switch (upload->getError()) {
|
||||
case AssetUpload::PermissionDenied:
|
||||
additionalError = PERMISSION_DENIED_ERROR;
|
||||
break;
|
||||
case AssetUpload::TooLarge:
|
||||
additionalError = "The uploaded content was too large and could not be stored in the asset-server.";
|
||||
break;
|
||||
case AssetUpload::ErrorLoadingFile:
|
||||
case AssetUpload::FileOpenError:
|
||||
additionalError = "The file could not be opened. Please check your permissions and try again.";
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
class QAction;
|
||||
|
||||
class AddressBarDialog;
|
||||
class AnimationsDialog;
|
||||
class AttachmentsDialog;
|
||||
class AudioStatsDialog;
|
||||
|
@ -29,13 +28,11 @@ class BandwidthDialog;
|
|||
class CachesSizeDialog;
|
||||
class DiskCacheEditor;
|
||||
class LodToolsDialog;
|
||||
class LoginDialog;
|
||||
class OctreeStatsDialog;
|
||||
class PreferencesDialog;
|
||||
class ScriptEditorWindow;
|
||||
class QMessageBox;
|
||||
class DomainConnectionDialog;
|
||||
class UpdateDialog;
|
||||
|
||||
class DialogsManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -94,7 +91,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
QPointer<AddressBarDialog> _addressBarDialog;
|
||||
QPointer<AnimationsDialog> _animationsDialog;
|
||||
QPointer<AttachmentsDialog> _attachmentsDialog;
|
||||
QPointer<AudioStatsDialog> _audioStatsDialog;
|
||||
|
@ -104,12 +100,10 @@ private:
|
|||
QPointer<QMessageBox> _ircInfoBox;
|
||||
QPointer<HMDToolsDialog> _hmdToolsDialog;
|
||||
QPointer<LodToolsDialog> _lodToolsDialog;
|
||||
QPointer<LoginDialog> _loginDialog;
|
||||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
QPointer<ScriptEditorWindow> _scriptEditor;
|
||||
QPointer<DomainConnectionDialog> _domainConnectionDialog;
|
||||
QPointer<UpdateDialog> _updateDialog;
|
||||
};
|
||||
|
||||
#endif // hifi_DialogsManager_h
|
||||
|
|
|
@ -40,7 +40,7 @@ void AnimInverseKinematics::loadPoses(const AnimPoseVec& poses) {
|
|||
void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) const {
|
||||
int numJoints = (int)_relativePoses.size();
|
||||
absolutePoses.clear();
|
||||
absolutePoses.reserve(numJoints);
|
||||
absolutePoses.resize(numJoints);
|
||||
assert(numJoints <= _skeleton->getNumJoints());
|
||||
for (int i = 0; i < numJoints; ++i) {
|
||||
int parentIndex = _skeleton->getParentIndex(i);
|
||||
|
|
|
@ -149,6 +149,7 @@ public:
|
|||
void set(const std::string& key, const glm::quat& value) { _map[key] = AnimVariant(value); }
|
||||
void set(const std::string& key, const glm::mat4& value) { _map[key] = AnimVariant(value); }
|
||||
void set(const std::string& key, const std::string& value) { _map[key] = AnimVariant(value); }
|
||||
void unset(const std::string& key) { _map.erase(key); }
|
||||
|
||||
void setTrigger(const std::string& key) { _triggers.insert(key); }
|
||||
void clearTriggers() { _triggers.clear(); }
|
||||
|
|
|
@ -30,6 +30,9 @@ void Rig::HeadParameters::dump() const {
|
|||
qCDebug(animation, " localHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
|
||||
axis = glm::axis(worldHeadOrientation);
|
||||
theta = glm::angle(worldHeadOrientation);
|
||||
qCDebug(animation, " localHead pitch = %.5f, yaw = %.5f, roll = %.5f", (double)localHeadPitch, (double)localHeadYaw, (double)localHeadRoll);
|
||||
qCDebug(animation, " localHeadPosition = (%.5f, %.5f, %.5f)", (double)localHeadPosition.x, (double)localHeadPosition.y, (double)localHeadPosition.z);
|
||||
qCDebug(animation, " isInHMD = %s", isInHMD ? "true" : "false");
|
||||
qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
|
||||
axis = glm::axis(modelRotation);
|
||||
theta = glm::angle(modelRotation);
|
||||
|
@ -953,56 +956,70 @@ void Rig::updateFromHeadParameters(const HeadParameters& params) {
|
|||
if (params.enableLean) {
|
||||
updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist);
|
||||
}
|
||||
updateNeckJoint(params.neckJointIndex, params.localHeadOrientation, params.leanSideways, params.leanForward, params.torsoTwist);
|
||||
updateNeckJoint(params.neckJointIndex, params);
|
||||
updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation,
|
||||
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
|
||||
}
|
||||
|
||||
static const glm::vec3 X_AXIS(1.0f, 0.0f, 0.0f);
|
||||
static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f);
|
||||
static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f);
|
||||
|
||||
void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) {
|
||||
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
|
||||
if (_enableAnimGraph && _animSkeleton) {
|
||||
glm::vec3 xAxis(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 zAxis(0.0f, 0.0f, 1.0f);
|
||||
glm::quat absRot = (glm::angleAxis(-RADIANS_PER_DEGREE * leanSideways, zAxis) *
|
||||
glm::angleAxis(-RADIANS_PER_DEGREE * leanForward, xAxis) *
|
||||
glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, yAxis));
|
||||
glm::quat absRot = (glm::angleAxis(-RADIANS_PER_DEGREE * leanSideways, Z_AXIS) *
|
||||
glm::angleAxis(-RADIANS_PER_DEGREE * leanForward, X_AXIS) *
|
||||
glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, Y_AXIS));
|
||||
_animVars.set("lean", absRot);
|
||||
} else if (!_enableAnimGraph) {
|
||||
auto& parentState = _jointStates[_jointStates[index].getParentIndex()];
|
||||
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::vec3 xAxis(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 zAxis(0.0f, 0.0f, 1.0f);
|
||||
glm::quat inverse = glm::inverse(parentState.getRotation() * getJointDefaultRotationInParentFrame(index));
|
||||
setJointRotationInConstrainedFrame(index,
|
||||
glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * zAxis) *
|
||||
glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * xAxis) *
|
||||
glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * yAxis) *
|
||||
glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * Z_AXIS) *
|
||||
glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * X_AXIS) *
|
||||
glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * Y_AXIS) *
|
||||
getJointState(index).getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist) {
|
||||
void Rig::updateNeckJoint(int index, const HeadParameters& params) {
|
||||
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
|
||||
auto& state = _jointStates[index];
|
||||
auto& parentState = _jointStates[state.getParentIndex()];
|
||||
if (_enableAnimGraph && _animSkeleton) {
|
||||
// the params.localHeadOrientation is composed incorrectly, so re-compose it correctly from pitch, yaw and roll.
|
||||
glm::quat realLocalHeadOrientation = (glm::angleAxis(glm::radians(-params.localHeadRoll), Z_AXIS) *
|
||||
glm::angleAxis(glm::radians(params.localHeadYaw), Y_AXIS) *
|
||||
glm::angleAxis(glm::radians(-params.localHeadPitch), X_AXIS));
|
||||
_animVars.set("headRotation", realLocalHeadOrientation);
|
||||
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::mat3 axes = glm::mat3_cast(glm::quat());
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() *
|
||||
glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) *
|
||||
state.getPreTransform() * glm::mat4_cast(state.getPreRotation())));
|
||||
glm::vec3 pitchYawRoll = safeEulerAngles(localHeadOrientation);
|
||||
glm::vec3 lean = glm::radians(glm::vec3(leanForward, torsoTwist, leanSideways));
|
||||
pitchYawRoll -= lean;
|
||||
setJointRotationInConstrainedFrame(index,
|
||||
glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) *
|
||||
state.getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
auto rootTrans = _animSkeleton->getAbsoluteBindPose(_rootJointIndex).trans;
|
||||
|
||||
if (params.isInHMD) {
|
||||
_animVars.set("headPosition", params.localHeadPosition + rootTrans);
|
||||
} else {
|
||||
_animVars.unset("headPosition");
|
||||
}
|
||||
} else if (!_enableAnimGraph) {
|
||||
|
||||
auto& state = _jointStates[index];
|
||||
auto& parentState = _jointStates[state.getParentIndex()];
|
||||
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() *
|
||||
glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) *
|
||||
state.getPreTransform() * glm::mat4_cast(state.getPreRotation())));
|
||||
glm::vec3 pitchYawRoll = safeEulerAngles(params.localHeadOrientation);
|
||||
glm::vec3 lean = glm::radians(glm::vec3(params.leanForward, params.torsoTwist, params.leanSideways));
|
||||
pitchYawRoll -= lean;
|
||||
setJointRotationInConstrainedFrame(index,
|
||||
glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * Z_AXIS)) *
|
||||
glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * Y_AXIS)) *
|
||||
glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * X_AXIS)) *
|
||||
state.getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,11 @@ public:
|
|||
bool enableLean = false;
|
||||
glm::quat modelRotation = glm::quat();
|
||||
glm::quat localHeadOrientation = glm::quat();
|
||||
float localHeadPitch = 0.0f; // degrees
|
||||
float localHeadYaw = 0.0f; // degrees
|
||||
float localHeadRoll = 0.0f; // degrees
|
||||
glm::vec3 localHeadPosition = glm::vec3();
|
||||
bool isInHMD = false;
|
||||
glm::quat worldHeadOrientation = glm::quat();
|
||||
glm::vec3 eyeLookAt = glm::vec3(); // world space
|
||||
glm::vec3 eyeSaccade = glm::vec3(); // world space
|
||||
|
@ -178,7 +183,7 @@ public:
|
|||
protected:
|
||||
|
||||
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
|
||||
void updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist);
|
||||
void updateNeckJoint(int index, const HeadParameters& params);
|
||||
void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade);
|
||||
|
||||
QVector<JointState> _jointStates;
|
||||
|
|
|
@ -113,10 +113,10 @@ void EntityTreeRenderer::init() {
|
|||
|
||||
if (_wantScripts) {
|
||||
_entitiesScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities",
|
||||
_scriptingServices->getControllerScriptingInterface());
|
||||
_scriptingServices->getControllerScriptingInterface(), false);
|
||||
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
|
||||
|
||||
_sandboxScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities Sandbox", NULL);
|
||||
_sandboxScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities Sandbox", NULL, false);
|
||||
}
|
||||
|
||||
// make sure our "last avatar position" is something other than our current position, so that on our
|
||||
|
@ -242,6 +242,7 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItemPointer entity, bool
|
|||
QString scriptContents = loadScriptContents(entityScript, isURL, isPending, url, reload);
|
||||
|
||||
if (isPending && isPreload && isURL) {
|
||||
//qDebug() << "attempted to load script, isPending, _waitingOnPreload.insert() url:" << url << "entityID:" << entityID;
|
||||
_waitingOnPreload.insert(url, entityID);
|
||||
}
|
||||
|
||||
|
@ -324,7 +325,8 @@ void EntityTreeRenderer::update() {
|
|||
QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, _lastMouseEvent);
|
||||
QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID);
|
||||
if (currentClickingEntity.property("holdingClickOnEntity").isValid()) {
|
||||
currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs);
|
||||
//qDebug() << "About to call holdingClickOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("holdingClickOnEntity", currentClickingEntity, currentClickingEntityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,7 +365,9 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
QScriptValueList entityArgs = createEntityArgs(entityID);
|
||||
QScriptValue entityScript = loadEntityScript(entityID);
|
||||
if (entityScript.property("leaveEntity").isValid()) {
|
||||
entityScript.property("leaveEntity").call(entityScript, entityArgs);
|
||||
|
||||
//qDebug() << "About to call leaveEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("leaveEntity", entityScript, entityArgs);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -376,7 +380,8 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
QScriptValueList entityArgs = createEntityArgs(entityID);
|
||||
QScriptValue entityScript = loadEntityScript(entityID);
|
||||
if (entityScript.property("enterEntity").isValid()) {
|
||||
entityScript.property("enterEntity").call(entityScript, entityArgs);
|
||||
//qDebug() << "About to call enterEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("enterEntity", entityScript, entityArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,7 +400,8 @@ void EntityTreeRenderer::leaveAllEntities() {
|
|||
QScriptValueList entityArgs = createEntityArgs(entityID);
|
||||
QScriptValue entityScript = loadEntityScript(entityID);
|
||||
if (entityScript.property("leaveEntity").isValid()) {
|
||||
entityScript.property("leaveEntity").call(entityScript, entityArgs);
|
||||
//qDebug() << "About to call leaveEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("leaveEntity", entityScript, entityArgs);
|
||||
}
|
||||
}
|
||||
_currentEntitiesInside.clear();
|
||||
|
@ -851,7 +857,7 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device
|
|||
bool precisionPicking = !_dontDoPrecisionPicking;
|
||||
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking);
|
||||
if (rayPickResult.intersects) {
|
||||
//qCDebug(entitiesrenderer) << "mousePressEvent over entity:" << rayPickResult.entityID;
|
||||
qCDebug(entitiesrenderer) << "mousePressEvent over entity:" << rayPickResult.entityID;
|
||||
|
||||
QString urlString = rayPickResult.properties.getHref();
|
||||
QUrl url = QUrl(urlString, QUrl::StrictMode);
|
||||
|
@ -865,13 +871,15 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device
|
|||
QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
|
||||
QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
|
||||
if (entityScript.property("mousePressOnEntity").isValid()) {
|
||||
entityScript.property("mousePressOnEntity").call(entityScript, entityScriptArgs);
|
||||
//qDebug() << "About to call mousePressOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("mousePressOnEntity", entityScript, entityScriptArgs);
|
||||
}
|
||||
|
||||
_currentClickingOnEntityID = rayPickResult.entityID;
|
||||
emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID));
|
||||
if (entityScript.property("clickDownOnEntity").isValid()) {
|
||||
entityScript.property("clickDownOnEntity").call(entityScript, entityScriptArgs);
|
||||
//qDebug() << "About to call clickDownOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("clickDownOnEntity", entityScript, entityScriptArgs);
|
||||
}
|
||||
} else {
|
||||
emit mousePressOffEntity(rayPickResult, event, deviceID);
|
||||
|
@ -897,7 +905,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi
|
|||
QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
|
||||
QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
|
||||
if (entityScript.property("mouseReleaseOnEntity").isValid()) {
|
||||
entityScript.property("mouseReleaseOnEntity").call(entityScript, entityScriptArgs);
|
||||
_entitiesScriptEngine->callScriptMethod("mouseReleaseOnEntity", entityScript, entityScriptArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -909,7 +917,8 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi
|
|||
QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID);
|
||||
QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID);
|
||||
if (currentClickingEntity.property("clickReleaseOnEntity").isValid()) {
|
||||
currentClickingEntity.property("clickReleaseOnEntity").call(currentClickingEntity, currentClickingEntityArgs);
|
||||
//qDebug() << "About to call clickReleaseOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("clickReleaseOnEntity", currentClickingEntity, currentClickingEntityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -937,11 +946,13 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
|
|||
// load the entity script if needed...
|
||||
QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
|
||||
if (entityScript.property("mouseMoveEvent").isValid()) {
|
||||
entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs);
|
||||
//qDebug() << "About to call mouseMoveEvent() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("mouseMoveEvent", entityScript, entityScriptArgs);
|
||||
}
|
||||
emit mouseMoveOnEntity(rayPickResult, event, deviceID);
|
||||
if (entityScript.property("mouseMoveOnEntity").isValid()) {
|
||||
entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs);
|
||||
//qDebug() << "About to call mouseMoveOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("mouseMoveOnEntity", entityScript, entityScriptArgs);
|
||||
}
|
||||
|
||||
// handle the hover logic...
|
||||
|
@ -955,7 +966,9 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
|
|||
|
||||
QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID);
|
||||
if (currentHoverEntity.property("hoverLeaveEntity").isValid()) {
|
||||
currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs);
|
||||
//qDebug() << "About to call hoverLeaveEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("hoverLeaveEntity", currentHoverEntity, currentHoverEntityArgs);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -964,7 +977,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
|
|||
if (rayPickResult.entityID != _currentHoverOverEntityID) {
|
||||
emit hoverEnterEntity(rayPickResult.entityID, MouseEvent(*event, deviceID));
|
||||
if (entityScript.property("hoverEnterEntity").isValid()) {
|
||||
entityScript.property("hoverEnterEntity").call(entityScript, entityScriptArgs);
|
||||
//qDebug() << "About to call hoverEnterEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("hoverEnterEntity", entityScript, entityScriptArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -972,7 +986,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
|
|||
// we should send our hover over event
|
||||
emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event, deviceID));
|
||||
if (entityScript.property("hoverOverEntity").isValid()) {
|
||||
entityScript.property("hoverOverEntity").call(entityScript, entityScriptArgs);
|
||||
//qDebug() << "About to call hoverOverEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("hoverOverEntity", entityScript, entityScriptArgs);
|
||||
}
|
||||
|
||||
// remember what we're hovering over
|
||||
|
@ -989,7 +1004,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
|
|||
|
||||
QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID);
|
||||
if (currentHoverEntity.property("hoverLeaveEntity").isValid()) {
|
||||
currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs);
|
||||
//qDebug() << "About to call hoverLeaveEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("hoverLeaveEntity", currentHoverEntity, currentHoverEntityArgs);
|
||||
}
|
||||
|
||||
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
|
||||
|
@ -1005,7 +1021,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
|
|||
|
||||
QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID);
|
||||
if (currentClickingEntity.property("holdingClickOnEntity").isValid()) {
|
||||
currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs);
|
||||
//qDebug() << "About to call holdingClickOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("holdingClickOnEntity", currentClickingEntity, currentClickingEntityArgs);
|
||||
}
|
||||
}
|
||||
_lastMouseEvent = MouseEvent(*event, deviceID);
|
||||
|
@ -1060,7 +1077,8 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const
|
|||
QScriptValue entityScript = loadEntityScript(entityID, true, reload); // is preload!
|
||||
if (entityScript.property("preload").isValid()) {
|
||||
QScriptValueList entityArgs = createEntityArgs(entityID);
|
||||
entityScript.property("preload").call(entityScript, entityArgs);
|
||||
//qDebug() << "About to call preload() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("preload", entityScript, entityArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1070,7 +1088,8 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) {
|
|||
QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID);
|
||||
if (entityScript.property("unload").isValid()) {
|
||||
QScriptValueList entityArgs = createEntityArgs(entityID);
|
||||
entityScript.property("unload").call(entityScript, entityArgs);
|
||||
//qDebug() << "About to call unload() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("unload", entityScript, entityArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1155,7 +1174,9 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
|
|||
args << idA.toScriptValue(_entitiesScriptEngine);
|
||||
args << idB.toScriptValue(_entitiesScriptEngine);
|
||||
args << collisionToScriptValue(_entitiesScriptEngine, collision);
|
||||
entityScriptA.property("collisionWithEntity").call(entityScriptA, args);
|
||||
|
||||
//qDebug() << "About to call collisionWithEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("collisionWithEntity", entityScriptA, args);
|
||||
}
|
||||
|
||||
emit collisionWithEntity(idB, idA, collision);
|
||||
|
@ -1165,7 +1186,9 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
|
|||
args << idB.toScriptValue(_entitiesScriptEngine);
|
||||
args << idA.toScriptValue(_entitiesScriptEngine);
|
||||
args << collisionToScriptValue(_entitiesScriptEngine, collision);
|
||||
entityScriptB.property("collisionWithEntity").call(entityScriptA, args);
|
||||
|
||||
//qDebug() << "About to call collisionWithEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread();
|
||||
_entitiesScriptEngine->callScriptMethod("collisionWithEntity", entityScriptB, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension,
|
|||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
|
||||
if (assetServer) {
|
||||
auto packetList = std::unique_ptr<NLPacketList>(new NLPacketList(PacketType::AssetUpload, QByteArray(), true, true));
|
||||
auto packetList = NLPacketList::create(PacketType::AssetUpload, QByteArray(), true, true);
|
||||
|
||||
auto messageID = ++_currentID;
|
||||
packetList->writePrimitive(messageID);
|
||||
|
|
|
@ -29,9 +29,9 @@ struct AssetInfo {
|
|||
int64_t size;
|
||||
};
|
||||
|
||||
using ReceivedAssetCallback = std::function<void(AssetServerError error, const QByteArray& data)>;
|
||||
using GetInfoCallback = std::function<void(AssetServerError error, AssetInfo info)>;
|
||||
using UploadResultCallback = std::function<void(AssetServerError error, const QString& hash)>;
|
||||
using ReceivedAssetCallback = std::function<void(AssetServerError serverError, const QByteArray& data)>;
|
||||
using GetInfoCallback = std::function<void(AssetServerError serverError, AssetInfo info)>;
|
||||
using UploadResultCallback = std::function<void(AssetServerError serverError, const QString& hash)>;
|
||||
|
||||
class AssetClient : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -41,14 +41,17 @@ void AssetRequest::start() {
|
|||
_state = WAITING_FOR_INFO;
|
||||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->getAssetInfo(_hash, _extension, [this](AssetServerError error, AssetInfo info) {
|
||||
assetClient->getAssetInfo(_hash, _extension, [this](AssetServerError serverError, AssetInfo info) {
|
||||
_info = info;
|
||||
_error = error;
|
||||
|
||||
if (_error != NoError) {
|
||||
if (serverError != AssetServerError::NoError) {
|
||||
qCDebug(networking) << "Got error retrieving asset info for" << _hash;
|
||||
|
||||
_state = FINISHED;
|
||||
emit finished(this);
|
||||
|
||||
_error = (serverError == AssetServerError::AssetNotFound) ? NotFound : UnknownError;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,17 +63,38 @@ void AssetRequest::start() {
|
|||
int start = 0, end = _info.size;
|
||||
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
assetClient->getAsset(_hash, _extension, start, end, [this, start, end](AssetServerError error,
|
||||
assetClient->getAsset(_hash, _extension, start, end, [this, start, end](AssetServerError serverError,
|
||||
const QByteArray& data) {
|
||||
Q_ASSERT(data.size() == (end - start));
|
||||
|
||||
_error = error;
|
||||
if (_error == NoError) {
|
||||
memcpy(_data.data() + start, data.constData(), data.size());
|
||||
_totalReceived += data.size();
|
||||
emit progress(_totalReceived, _info.size);
|
||||
if (serverError == AssetServerError::NoError) {
|
||||
|
||||
// we need to check the hash of the received data to make sure it matches what we expect
|
||||
if (hashData(data).toHex() == _hash) {
|
||||
memcpy(_data.data() + start, data.constData(), data.size());
|
||||
_totalReceived += data.size();
|
||||
emit progress(_totalReceived, _info.size);
|
||||
} else {
|
||||
// hash doesn't match - we have an error
|
||||
_error = HashVerificationFailed;
|
||||
}
|
||||
|
||||
} else {
|
||||
qCDebug(networking) << "Got error retrieving asset" << _hash;
|
||||
switch (serverError) {
|
||||
case AssetServerError::AssetNotFound:
|
||||
_error = NotFound;
|
||||
break;
|
||||
case AssetServerError::InvalidByteRange:
|
||||
_error = InvalidByteRange;
|
||||
break;
|
||||
default:
|
||||
_error = UnknownError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_error != NoError) {
|
||||
qCDebug(networking) << "Got error retrieving asset" << _hash << "- error code" << _error;
|
||||
}
|
||||
|
||||
_state = FINISHED;
|
||||
|
|
|
@ -29,14 +29,22 @@ public:
|
|||
WAITING_FOR_DATA,
|
||||
FINISHED
|
||||
};
|
||||
|
||||
enum Error {
|
||||
NoError,
|
||||
NotFound,
|
||||
InvalidByteRange,
|
||||
HashVerificationFailed,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
AssetRequest(QObject* parent, const QString& hash, const QString& extension);
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
const QByteArray& getData() const { return _data; }
|
||||
State getState() const { return _state; }
|
||||
AssetServerError getError() const { return _error; }
|
||||
const State& getState() const { return _state; }
|
||||
const Error& getError() const { return _error; }
|
||||
|
||||
signals:
|
||||
void finished(AssetRequest* thisRequest);
|
||||
|
@ -44,7 +52,7 @@ signals:
|
|||
|
||||
private:
|
||||
State _state = NOT_STARTED;
|
||||
AssetServerError _error;
|
||||
Error _error = NoError;
|
||||
AssetInfo _info;
|
||||
uint64_t _totalReceived { 0 };
|
||||
QString _hash;
|
||||
|
|
|
@ -48,11 +48,11 @@ void AssetResourceRequest::doSend() {
|
|||
Q_ASSERT(req->getState() == AssetRequest::FINISHED);
|
||||
|
||||
switch (req->getError()) {
|
||||
case NoError:
|
||||
case AssetRequest::Error::NoError:
|
||||
_data = req->getData();
|
||||
_result = Success;
|
||||
break;
|
||||
case AssetNotFound:
|
||||
case AssetRequest::Error::NotFound:
|
||||
_result = NotFound;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -46,23 +46,23 @@ void AssetUpload::start() {
|
|||
assetClient->uploadAsset(data, _extension, [this](AssetServerError error, const QString& hash){
|
||||
switch (error) {
|
||||
case AssetServerError::NoError:
|
||||
_result = Success;
|
||||
_error = NoError;
|
||||
break;
|
||||
case AssetServerError::AssetTooLarge:
|
||||
_result = TooLarge;
|
||||
_error = TooLarge;
|
||||
break;
|
||||
case AssetServerError::PermissionDenied:
|
||||
_result = PermissionDenied;
|
||||
_error = PermissionDenied;
|
||||
break;
|
||||
default:
|
||||
_result = ErrorLoadingFile;
|
||||
_error = FileOpenError;
|
||||
break;
|
||||
}
|
||||
emit finished(this, hash);
|
||||
});
|
||||
} else {
|
||||
// we couldn't open the file - set the error result
|
||||
_result = ErrorLoadingFile;
|
||||
_error = FileOpenError;
|
||||
|
||||
// emit that we are done
|
||||
emit finished(this, QString());
|
||||
|
|
|
@ -26,12 +26,12 @@ class AssetUpload : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum Result {
|
||||
Success = 0,
|
||||
enum Error {
|
||||
NoError = 0,
|
||||
Timeout,
|
||||
TooLarge,
|
||||
PermissionDenied,
|
||||
ErrorLoadingFile
|
||||
FileOpenError
|
||||
};
|
||||
|
||||
AssetUpload(QObject* parent, const QString& filename);
|
||||
|
@ -40,7 +40,7 @@ public:
|
|||
|
||||
const QString& getFilename() const { return _filename; }
|
||||
const QString& getExtension() const { return _extension; }
|
||||
const Result& getResult() const { return _result; }
|
||||
const Error& getError() const { return _error; }
|
||||
|
||||
signals:
|
||||
void finished(AssetUpload* upload, const QString& hash);
|
||||
|
@ -49,7 +49,7 @@ signals:
|
|||
private:
|
||||
QString _filename;
|
||||
QString _extension;
|
||||
Result _result;
|
||||
Error _error;
|
||||
};
|
||||
|
||||
#endif // hifi_AssetUpload_h
|
||||
|
|
|
@ -1,338 +0,0 @@
|
|||
//
|
||||
// JSONBreakableMarshal.cpp
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Stephen Birarda on 04/28/15.
|
||||
// Copyright 2015 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 "JSONBreakableMarshal.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
QVariantMap JSONBreakableMarshal::_interpolationMap = QVariantMap();
|
||||
|
||||
QStringList JSONBreakableMarshal::toStringList(const QJsonValue& jsonValue, const QString& keypath) {
|
||||
// setup the string list that will hold our result
|
||||
QStringList result;
|
||||
|
||||
// figure out what type of value this is so we know how to act on it
|
||||
if (jsonValue.isObject()) {
|
||||
|
||||
QJsonObject jsonObject = jsonValue.toObject();
|
||||
|
||||
// enumerate the keys of the QJsonObject
|
||||
foreach(const QString& key, jsonObject.keys()) {
|
||||
QJsonValue childValue = jsonObject[key];
|
||||
|
||||
// setup the keypath for this key
|
||||
QString valueKeypath = (keypath.isEmpty() ? "" : keypath + ".") + key;
|
||||
|
||||
if (childValue.isObject() || childValue.isArray()) {
|
||||
// recursion is required since the value is a QJsonObject or QJsonArray
|
||||
result << toStringList(childValue, valueKeypath);
|
||||
} else {
|
||||
// no recursion required, call our toString method to get the string representation
|
||||
// append the QStringList resulting from that to our QStringList
|
||||
result << toString(childValue, valueKeypath);
|
||||
}
|
||||
}
|
||||
} else if (jsonValue.isArray()) {
|
||||
QJsonArray jsonArray = jsonValue.toArray();
|
||||
|
||||
// enumerate the elements in this QJsonArray
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
QJsonValue arrayValue = jsonArray[i];
|
||||
|
||||
// setup the keypath for this object with the array index
|
||||
QString valueKeypath = QString("%1[%2]").arg(keypath).arg(i);
|
||||
|
||||
if (arrayValue.isObject() || arrayValue.isArray()) {
|
||||
// recursion is required since the value is a QJsonObject or QJsonArray
|
||||
// append the QStringList resulting from that to our QStringList
|
||||
result << toStringList(arrayValue, valueKeypath);
|
||||
} else {
|
||||
result << toString(arrayValue, valueKeypath);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this is a basic value, so set result to whatever toString reports in a QStringList
|
||||
result = QStringList() << toString(jsonValue, keypath);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const QString JSON_NULL_AS_STRING = "null";
|
||||
const QString JSON_TRUE_AS_STRING = "true";
|
||||
const QString JSON_FALSE_AS_STRING = "false";
|
||||
const QString JSON_UNDEFINED_AS_STRING = "undefined";
|
||||
const QString JSON_UNKNOWN_AS_STRING = "unknown";
|
||||
|
||||
QString JSONBreakableMarshal::toString(const QJsonValue& jsonValue, const QString& keypath) {
|
||||
// default the value as a string to unknown in case conversion fails
|
||||
QString valueAsString = JSON_UNKNOWN_AS_STRING;
|
||||
|
||||
// ask the QJsonValue what type it is and format its value as a string accordingly
|
||||
if (jsonValue.isNull()) {
|
||||
valueAsString = JSON_NULL_AS_STRING;
|
||||
} else if (jsonValue.isBool()) {
|
||||
valueAsString = jsonValue.toBool() ? JSON_TRUE_AS_STRING : JSON_FALSE_AS_STRING;
|
||||
} else if (jsonValue.isDouble()) {
|
||||
valueAsString = QString::number(jsonValue.toDouble());
|
||||
} else if (jsonValue.isString()) {
|
||||
valueAsString = QString("\"%1\"").arg(jsonValue.toString());
|
||||
} else if (jsonValue.isUndefined()) {
|
||||
valueAsString = JSON_UNDEFINED_AS_STRING;
|
||||
} else if (jsonValue.isArray() || jsonValue.isObject()) {
|
||||
qDebug() << "JSONBreakableMarshal::toString does not handle conversion of a QJsonObject or QJsonArray."
|
||||
<< "You should call JSONBreakableMarshal::toStringList instead.";
|
||||
} else {
|
||||
qDebug() << "Unrecognized QJsonValue - JSONBreakableMarshal cannot convert to string.";
|
||||
}
|
||||
|
||||
return QString("%1=%2").arg(keypath, valueAsString);
|
||||
}
|
||||
|
||||
QVariant JSONBreakableMarshal::fromString(const QString& marshalValue) {
|
||||
// default the value to null
|
||||
QVariant result;
|
||||
|
||||
// attempt to match the value with our expected strings
|
||||
if (marshalValue == JSON_NULL_AS_STRING) {
|
||||
// this is already our default, we don't need to do anything here
|
||||
} else if (marshalValue == JSON_TRUE_AS_STRING || marshalValue == JSON_FALSE_AS_STRING) {
|
||||
result = QVariant(marshalValue == JSON_TRUE_AS_STRING ? true : false);
|
||||
} else if (marshalValue == JSON_UNDEFINED_AS_STRING) {
|
||||
result = JSON_UNDEFINED_AS_STRING;
|
||||
} else if (marshalValue == JSON_UNKNOWN_AS_STRING) {
|
||||
// we weren't able to marshal this value at the other end, set it as our unknown string
|
||||
result = JSON_UNKNOWN_AS_STRING;
|
||||
} else {
|
||||
// this might be a double, see if it converts
|
||||
bool didConvert = false;
|
||||
double convertResult = marshalValue.toDouble(&didConvert);
|
||||
|
||||
if (didConvert) {
|
||||
result = convertResult;
|
||||
} else {
|
||||
// we need to figure out if this is a string
|
||||
// use a regex to look for surrounding quotes first
|
||||
const QString JSON_STRING_REGEX = "^\"([\\s\\S]*)\"$";
|
||||
QRegExp stringRegex(JSON_STRING_REGEX);
|
||||
|
||||
if (stringRegex.indexIn(marshalValue) != -1) {
|
||||
// set the result to the string value
|
||||
result = stringRegex.cap(1);
|
||||
} else {
|
||||
// we failed to convert the value to anything, set the result to our unknown value
|
||||
qDebug() << "Unrecognized output from JSONBreakableMarshal - could not convert"
|
||||
<< marshalValue << "to QVariant.";
|
||||
result = JSON_UNKNOWN_AS_STRING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariantMap JSONBreakableMarshal::fromStringList(const QStringList& stringList) {
|
||||
QVariant result = QVariantMap();
|
||||
|
||||
foreach(const QString& marshalString, stringList) {
|
||||
|
||||
// find the equality operator
|
||||
int equalityIndex = marshalString.indexOf('=');
|
||||
|
||||
// bail on parsing if we didn't find the equality operator
|
||||
if (equalityIndex != -1) {
|
||||
|
||||
QVariant* currentValue = &result;
|
||||
|
||||
// pull the key (everything left of the equality sign)
|
||||
QString parentKeypath;
|
||||
QString keypath = marshalString.left(equalityIndex);
|
||||
|
||||
// setup for array index checking
|
||||
const QString ARRAY_INDEX_REGEX_STRING = "\\[(\\d+)\\]";
|
||||
QRegExp arrayRegex(ARRAY_INDEX_REGEX_STRING);
|
||||
|
||||
// as long as we have a keypath we need to recurse downwards
|
||||
while (!keypath.isEmpty()) {
|
||||
parentKeypath = keypath;
|
||||
|
||||
int arrayBracketIndex = arrayRegex.indexIn(keypath);
|
||||
|
||||
// is this an array index
|
||||
if (arrayBracketIndex == 0) {
|
||||
// we're here because we think the current value should be an array
|
||||
// if it isn't then make one
|
||||
if (!currentValue->canConvert(QMetaType::QVariantList) || currentValue->isNull()) {
|
||||
*currentValue = QVariantList();
|
||||
}
|
||||
|
||||
QVariantList& currentList = *static_cast<QVariantList*>(currentValue->data());
|
||||
|
||||
// figure out what index we want to get the QJsonValue& for
|
||||
bool didConvert = false;
|
||||
int arrayIndex = arrayRegex.cap(1).toInt(&didConvert);
|
||||
|
||||
if (didConvert) {
|
||||
// check if we need to resize the array
|
||||
if (currentList.size() < arrayIndex + 1) {
|
||||
|
||||
for (int i = currentList.size(); i < arrayIndex + 1; i++) {
|
||||
// add the null QJsonValue at this array index to get the array to the right size
|
||||
currentList.push_back(QJsonValue());
|
||||
}
|
||||
}
|
||||
|
||||
// set our currentValue to the QJsonValue& from the array at this index
|
||||
currentValue = ¤tList[arrayIndex];
|
||||
|
||||
// update the keypath by bumping past the array index
|
||||
keypath = keypath.mid(keypath.indexOf(']') + 1);
|
||||
|
||||
// check if there is a key after the array index - if so push the keypath forward by a char
|
||||
if (keypath.startsWith(".")) {
|
||||
keypath = keypath.mid(1);
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Failed to convert array index from keypath" << keypath << "to int. Will not add"
|
||||
<< "value to resulting QJsonObject.";
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
int keySeparatorIndex = keypath.indexOf('.');
|
||||
|
||||
// we need to figure out what the key to look at is
|
||||
QString subKey = keypath;
|
||||
|
||||
if (keySeparatorIndex != -1 || arrayBracketIndex != -1) {
|
||||
int nextBreakIndex = -1;
|
||||
int nextKeypathStartIndex = -1;
|
||||
|
||||
if (arrayBracketIndex == -1 || (keySeparatorIndex != -1 && keySeparatorIndex < arrayBracketIndex)) {
|
||||
nextBreakIndex = keySeparatorIndex;
|
||||
nextKeypathStartIndex = keySeparatorIndex + 1;
|
||||
} else if (keySeparatorIndex == -1 || (arrayBracketIndex != -1
|
||||
&& arrayBracketIndex < keySeparatorIndex)) {
|
||||
nextBreakIndex = arrayBracketIndex;
|
||||
nextKeypathStartIndex = arrayBracketIndex;
|
||||
} else {
|
||||
qDebug() << "Unrecognized key format while trying to parse " << keypath << " - will not add"
|
||||
<< "value to resulting QJsonObject.";
|
||||
break;
|
||||
}
|
||||
|
||||
// set the current key from the determined index
|
||||
subKey = keypath.left(nextBreakIndex);
|
||||
|
||||
// update the keypath being processed
|
||||
keypath = keypath.mid(nextKeypathStartIndex);
|
||||
|
||||
} else {
|
||||
// update the keypath being processed, since we have no more separators in the keypath, it should
|
||||
// be an empty string
|
||||
keypath = "";
|
||||
}
|
||||
|
||||
// we're here becuase we know the current value should be an object
|
||||
// if it isn't then make it one
|
||||
|
||||
if (!currentValue->canConvert(QMetaType::QVariantMap) || currentValue->isNull()) {
|
||||
*currentValue = QVariantMap();
|
||||
}
|
||||
|
||||
QVariantMap& currentMap = *static_cast<QVariantMap*>(currentValue->data());
|
||||
|
||||
// is there a QJsonObject for this key yet?
|
||||
// if not then we make it now
|
||||
if (!currentMap.contains(subKey)) {
|
||||
currentMap[subKey] = QVariant();
|
||||
}
|
||||
|
||||
// change the currentValue to the QJsonValue for this key
|
||||
currentValue = ¤tMap[subKey];
|
||||
}
|
||||
}
|
||||
|
||||
*currentValue = fromString(marshalString.mid(equalityIndex + 1));
|
||||
|
||||
if (_interpolationMap.contains(parentKeypath)) {
|
||||
// we expect the currentValue here to be a string, that's the key we use for interpolation
|
||||
// bail if it isn't
|
||||
if (currentValue->canConvert(QMetaType::QString)
|
||||
&& _interpolationMap[parentKeypath].canConvert(QMetaType::QVariantMap)) {
|
||||
*currentValue = _interpolationMap[parentKeypath].toMap()[currentValue->toString()];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toMap();
|
||||
}
|
||||
|
||||
QVariantMap JSONBreakableMarshal::fromStringBuffer(const QByteArray& buffer) {
|
||||
// this is a packet of strings sep by null terminators - pull out each string and create a stringlist
|
||||
QStringList packetList;
|
||||
int currentIndex = 0;
|
||||
int currentSeparator = buffer.indexOf('\0');
|
||||
|
||||
while (currentIndex < buffer.size() - 1) {
|
||||
packetList << QString::fromUtf8(buffer.mid(currentIndex, currentSeparator));
|
||||
|
||||
if (currentSeparator == -1) {
|
||||
// no more separators to be found, break out of here so we're not looping for nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// bump the currentIndex up to the last found separator
|
||||
currentIndex = currentSeparator + 1;
|
||||
|
||||
// find the index of the next separator, assuming this one wasn't the last one in the packet
|
||||
if (currentSeparator < buffer.size() - 1) {
|
||||
currentSeparator = buffer.indexOf('\0', currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// now that we have a QStringList we use our static method to turn that into a QJsonObject
|
||||
return fromStringList(packetList);
|
||||
}
|
||||
|
||||
void JSONBreakableMarshal::addInterpolationForKey(const QString& rootKey, const QString& interpolationKey,
|
||||
const QJsonValue& interpolationValue) {
|
||||
// if there is no map already beneath this key in our _interpolationMap create a QVariantMap there now
|
||||
|
||||
if (!_interpolationMap.contains(rootKey)) {
|
||||
_interpolationMap.insert(rootKey, QVariantMap());
|
||||
}
|
||||
|
||||
if (_interpolationMap[rootKey].canConvert(QMetaType::QVariantMap)) {
|
||||
QVariantMap& mapForRootKey = *static_cast<QVariantMap*>(_interpolationMap[rootKey].data());
|
||||
|
||||
mapForRootKey.insert(interpolationKey, QVariant(interpolationValue));
|
||||
} else {
|
||||
qDebug() << "JSONBreakableMarshal::addInterpolationForKey could not convert variant at key" << rootKey
|
||||
<< "to a QVariantMap. Can not add interpolation.";
|
||||
}
|
||||
}
|
||||
|
||||
void JSONBreakableMarshal::removeInterpolationForKey(const QString& rootKey, const QString& interpolationKey) {
|
||||
// make sure the interpolation map contains this root key and that the value is a map
|
||||
|
||||
if (_interpolationMap.contains(rootKey)) {
|
||||
QVariant& rootValue = _interpolationMap[rootKey];
|
||||
|
||||
if (!rootValue.isNull() && rootValue.canConvert(QMetaType::QVariantMap)) {
|
||||
// remove the value at the interpolationKey
|
||||
static_cast<QVariantMap*>(rootValue.data())->remove(interpolationKey);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
//
|
||||
// JSONBreakableMarshal.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Stephen Birarda on 04/28/15.
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
#ifndef hifi_JSONBreakableMarshal_h
|
||||
#define hifi_JSONBreakableMarshal_h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QJsonValue>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariantMap>
|
||||
|
||||
class JSONBreakableMarshal {
|
||||
public:
|
||||
static QStringList toStringList(const QJsonValue& jsonValue, const QString& keypath);
|
||||
static QString toString(const QJsonValue& jsonValue, const QString& keyPath);
|
||||
|
||||
static QVariant fromString(const QString& marshalValue);
|
||||
static QVariantMap fromStringList(const QStringList& stringList);
|
||||
static QVariantMap fromStringBuffer(const QByteArray& buffer);
|
||||
|
||||
static void addInterpolationForKey(const QString& rootKey,
|
||||
const QString& interpolationKey, const QJsonValue& interpolationValue);
|
||||
static void removeInterpolationForKey(const QString& rootKey, const QString& interpolationKey);
|
||||
|
||||
private:
|
||||
static QVariantMap _interpolationMap;
|
||||
};
|
||||
|
||||
#endif // hifi_JSONBreakableMarshal_h
|
|
@ -355,6 +355,12 @@ qint64 LimitedNodeList::sendPacketList(std::unique_ptr<NLPacketList> packetList,
|
|||
// close the last packet in the list
|
||||
packetList->closeCurrentPacket();
|
||||
|
||||
for (std::unique_ptr<udt::Packet>& packet : packetList->_packets) {
|
||||
NLPacket* nlPacket = static_cast<NLPacket*>(packet.get());
|
||||
collectPacketStats(*nlPacket);
|
||||
fillPacketHeader(*nlPacket);
|
||||
}
|
||||
|
||||
return _nodeSocket.writePacketList(std::move(packetList), sockAddr);
|
||||
}
|
||||
|
||||
|
@ -410,11 +416,12 @@ void LimitedNodeList::eraseAllNodes() {
|
|||
killedNodes.insert(node);
|
||||
});
|
||||
|
||||
// iterate the current nodes, emit that they are dying and remove them from the hash
|
||||
_nodeMutex.lockForWrite();
|
||||
_nodeHash.clear();
|
||||
_nodeMutex.unlock();
|
||||
|
||||
{
|
||||
// iterate the current nodes, emit that they are dying and remove them from the hash
|
||||
QWriteLocker writeLocker(&_nodeMutex);
|
||||
_nodeHash.clear();
|
||||
}
|
||||
|
||||
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
||||
handleNodeKill(killedNode);
|
||||
}
|
||||
|
@ -428,21 +435,20 @@ void LimitedNodeList::reset() {
|
|||
}
|
||||
|
||||
void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
||||
_nodeMutex.lockForRead();
|
||||
QReadLocker readLocker(&_nodeMutex);
|
||||
|
||||
NodeHash::iterator it = _nodeHash.find(nodeUUID);
|
||||
if (it != _nodeHash.end()) {
|
||||
SharedNodePointer matchingNode = it->second;
|
||||
|
||||
_nodeMutex.unlock();
|
||||
|
||||
_nodeMutex.lockForWrite();
|
||||
_nodeHash.unsafe_erase(it);
|
||||
_nodeMutex.unlock();
|
||||
|
||||
readLocker.unlock();
|
||||
|
||||
{
|
||||
QWriteLocker writeLocker(&_nodeMutex);
|
||||
_nodeHash.unsafe_erase(it);
|
||||
}
|
||||
|
||||
handleNodeKill(matchingNode);
|
||||
} else {
|
||||
_nodeMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -839,6 +845,14 @@ void LimitedNodeList::sendPeerQueryToIceServer(const HifiSockAddr& iceServerSock
|
|||
sendPacketToIceServer(PacketType::ICEServerQuery, iceServerSockAddr, clientID, peerID);
|
||||
}
|
||||
|
||||
SharedNodePointer LimitedNodeList::findNodeWithAddr(const HifiSockAddr& addr) {
|
||||
QReadLocker locker(&_nodeMutex);
|
||||
auto it = std::find_if(std::begin(_nodeHash), std::end(_nodeHash), [&](const UUIDNodePair& pair) {
|
||||
return pair.second->getActiveSocket() ? (*pair.second->getActiveSocket() == addr) : false;
|
||||
});
|
||||
return (it != std::end(_nodeHash)) ? it->second : SharedNodePointer();
|
||||
}
|
||||
|
||||
void LimitedNodeList::sendPacketToIceServer(PacketType packetType, const HifiSockAddr& iceServerSockAddr,
|
||||
const QUuid& clientID, const QUuid& peerID) {
|
||||
auto icePacket = NLPacket::create(packetType);
|
||||
|
|
|
@ -165,6 +165,8 @@ public:
|
|||
void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr);
|
||||
void sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID);
|
||||
|
||||
SharedNodePointer findNodeWithAddr(const HifiSockAddr& addr);
|
||||
|
||||
template<typename NodeLambda>
|
||||
void eachNode(NodeLambda functor) {
|
||||
QReadLocker readLock(&_nodeMutex);
|
||||
|
@ -216,6 +218,7 @@ public:
|
|||
{ QReadLocker readLock(&_connectionTimeLock); return _lastConnectionTimes; }
|
||||
void flagTimeForConnectionStep(ConnectionStep connectionStep);
|
||||
|
||||
udt::Socket::StatsVector sampleStatsForAllConnections() { return _nodeSocket.sampleStatsForAllConnections(); }
|
||||
|
||||
public slots:
|
||||
void reset();
|
||||
|
@ -254,7 +257,7 @@ protected:
|
|||
qint64 writePacket(const NLPacket& packet, const HifiSockAddr& destinationSockAddr,
|
||||
const QUuid& connectionSecret = QUuid());
|
||||
void collectPacketStats(const NLPacket& packet);
|
||||
void fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret);
|
||||
void fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret = QUuid());
|
||||
|
||||
bool isPacketVerified(const udt::Packet& packet);
|
||||
bool packetVersionMatch(const udt::Packet& packet);
|
||||
|
|
|
@ -13,16 +13,30 @@
|
|||
|
||||
#include "udt/Packet.h"
|
||||
|
||||
|
||||
std::unique_ptr<NLPacketList> NLPacketList::create(PacketType packetType, QByteArray extendedHeader,
|
||||
bool isReliable, bool isOrdered) {
|
||||
auto nlPacketList = std::unique_ptr<NLPacketList>(new NLPacketList(packetType, extendedHeader,
|
||||
isReliable, isOrdered));
|
||||
nlPacketList->open(WriteOnly);
|
||||
return nlPacketList;
|
||||
}
|
||||
|
||||
std::unique_ptr<NLPacketList> NLPacketList::fromPacketList(std::unique_ptr<PacketList> packetList) {
|
||||
auto nlPacketList = std::unique_ptr<NLPacketList>(new NLPacketList(std::move(*packetList.release()))); nlPacketList->open(ReadOnly);
|
||||
return nlPacketList;
|
||||
}
|
||||
|
||||
|
||||
NLPacketList::NLPacketList(PacketType packetType, QByteArray extendedHeader, bool isReliable, bool isOrdered) :
|
||||
PacketList(packetType, extendedHeader, isReliable, isOrdered)
|
||||
{
|
||||
}
|
||||
|
||||
NLPacketList::NLPacketList(PacketList&& other) : PacketList(other.getType(), other.getExtendedHeader(), other.isReliable(), other.isOrdered()) {
|
||||
NLPacketList::NLPacketList(PacketList&& other) : PacketList(std::move(other)) {
|
||||
// Update _packets
|
||||
for (auto& packet : other._packets) {
|
||||
auto nlPacket = NLPacket::fromBase(std::move(packet));
|
||||
_packets.push_back(std::move(nlPacket));
|
||||
for (auto& packet : _packets) {
|
||||
packet = NLPacket::fromBase(std::move(packet));
|
||||
}
|
||||
|
||||
if (_packets.size() > 0) {
|
||||
|
|
|
@ -18,12 +18,17 @@
|
|||
|
||||
class NLPacketList : public udt::PacketList {
|
||||
public:
|
||||
NLPacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false);
|
||||
NLPacketList(PacketList&& packetList);
|
||||
static std::unique_ptr<NLPacketList> create(PacketType packetType, QByteArray extendedHeader = QByteArray(),
|
||||
bool isReliable = false, bool isOrdered = false);
|
||||
|
||||
static std::unique_ptr<NLPacketList> fromPacketList(std::unique_ptr<PacketList>);
|
||||
|
||||
const QUuid& getSourceID() const { return _sourceID; }
|
||||
|
||||
private:
|
||||
NLPacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false,
|
||||
bool isOrdered = false);
|
||||
NLPacketList(PacketList&& packetList);
|
||||
NLPacketList(const NLPacketList& other) = delete;
|
||||
NLPacketList& operator=(const NLPacketList& other) = delete;
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "AddressManager.h"
|
||||
#include "Assignment.h"
|
||||
#include "HifiSockAddr.h"
|
||||
#include "JSONBreakableMarshal.h"
|
||||
|
||||
#include "NetworkLogging.h"
|
||||
#include "udt/PacketHeaders.h"
|
||||
|
@ -107,20 +106,12 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
|||
}
|
||||
|
||||
qint64 NodeList::sendStats(const QJsonObject& statsObject, const HifiSockAddr& destination) {
|
||||
NLPacketList statsPacketList(PacketType::NodeJsonStats);
|
||||
auto statsPacketList = NLPacketList::create(PacketType::NodeJsonStats, QByteArray(), true, true);
|
||||
|
||||
// get a QStringList using JSONBreakableMarshal
|
||||
QStringList statsStringList = JSONBreakableMarshal::toStringList(statsObject, "");
|
||||
QJsonDocument jsonDocument(statsObject);
|
||||
statsPacketList->write(jsonDocument.toBinaryData());
|
||||
|
||||
// enumerate the resulting strings - pack them and send off packets via NLPacketList
|
||||
foreach(const QString& statsItem, statsStringList) {
|
||||
QByteArray utf8String = statsItem.toUtf8();
|
||||
utf8String.append('\0');
|
||||
|
||||
statsPacketList.write(utf8String);
|
||||
}
|
||||
|
||||
sendPacketList(statsPacketList, destination);
|
||||
sendPacketList(std::move(statsPacketList), destination);
|
||||
|
||||
// enumerate the resulting strings, breaking them into MTU sized packets
|
||||
return 0;
|
||||
|
|
|
@ -247,7 +247,7 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr<udt::PacketList> p
|
|||
}
|
||||
|
||||
// setup an NLPacketList from the PacketList we were passed
|
||||
auto nlPacketList = new NLPacketList(std::move(*packetList));
|
||||
auto nlPacketList = NLPacketList::fromPacketList(std::move(packetList));
|
||||
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
|
@ -297,21 +297,21 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr<udt::PacketList> p
|
|||
success = metaMethod.invoke(listener.first,
|
||||
connectionType,
|
||||
Q_ARG(QSharedPointer<NLPacketList>,
|
||||
QSharedPointer<NLPacketList>(nlPacketList)),
|
||||
QSharedPointer<NLPacketList>(nlPacketList.release())),
|
||||
Q_ARG(SharedNodePointer, matchingNode));
|
||||
|
||||
} else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) {
|
||||
success = metaMethod.invoke(listener.first,
|
||||
connectionType,
|
||||
Q_ARG(QSharedPointer<NLPacketList>,
|
||||
QSharedPointer<NLPacketList>(nlPacketList)),
|
||||
QSharedPointer<NLPacketList>(nlPacketList.release())),
|
||||
Q_ARG(QSharedPointer<Node>, matchingNode));
|
||||
|
||||
} else {
|
||||
success = metaMethod.invoke(listener.first,
|
||||
connectionType,
|
||||
Q_ARG(QSharedPointer<NLPacketList>,
|
||||
QSharedPointer<NLPacketList>(nlPacketList)));
|
||||
QSharedPointer<NLPacketList>(nlPacketList.release())));
|
||||
}
|
||||
} else {
|
||||
listenerIsDead = true;
|
||||
|
@ -323,7 +323,7 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr<udt::PacketList> p
|
|||
if (listener.first) {
|
||||
success = listener.second.invoke(listener.first,
|
||||
Q_ARG(QSharedPointer<NLPacketList>,
|
||||
QSharedPointer<NLPacketList>(nlPacketList)));
|
||||
QSharedPointer<NLPacketList>(nlPacketList.release())));
|
||||
} else {
|
||||
listenerIsDead = true;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@ public:
|
|||
static std::unique_ptr<BasePacket> create(qint64 size = -1);
|
||||
static std::unique_ptr<BasePacket> fromReceivedPacket(std::unique_ptr<char[]> data, qint64 size,
|
||||
const HifiSockAddr& senderSockAddr);
|
||||
|
||||
|
||||
|
||||
// Current level's header size
|
||||
static int localHeaderSize();
|
||||
|
@ -72,8 +70,8 @@ public:
|
|||
virtual bool isSequential() const { return false; }
|
||||
virtual bool reset();
|
||||
virtual qint64 size() const { return _payloadCapacity; }
|
||||
|
||||
using QIODevice::read;
|
||||
|
||||
using QIODevice::read; // Bring QIODevice::read methods to scope, otherwise they are hidden by folling method
|
||||
QByteArray read(qint64 maxSize);
|
||||
QByteArray readWithoutCopy(qint64 maxSize); // this can only be used if packet will stay in scope
|
||||
|
||||
|
@ -107,16 +105,16 @@ protected:
|
|||
};
|
||||
|
||||
template<typename T> qint64 BasePacket::peekPrimitive(T* data) {
|
||||
return QIODevice::peek(reinterpret_cast<char*>(data), sizeof(T));
|
||||
return peek(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> qint64 BasePacket::readPrimitive(T* data) {
|
||||
return QIODevice::read(reinterpret_cast<char*>(data), sizeof(T));
|
||||
return read(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> qint64 BasePacket::writePrimitive(const T& data) {
|
||||
static_assert(!std::is_pointer<T>::value, "T must not be a pointer");
|
||||
return QIODevice::write(reinterpret_cast<const char*>(&data), sizeof(T));
|
||||
return write(reinterpret_cast<const char*>(&data), sizeof(T));
|
||||
}
|
||||
|
||||
} // namespace udt
|
||||
|
|
|
@ -15,7 +15,7 @@ using namespace udt;
|
|||
using namespace std::chrono;
|
||||
|
||||
ConnectionStats::ConnectionStats() {
|
||||
auto now = duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch());
|
||||
auto now = duration_cast<microseconds>(system_clock::now().time_since_epoch());
|
||||
_currentSample.startTime = now;
|
||||
_total.startTime = now;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ ConnectionStats::Stats ConnectionStats::sample() {
|
|||
Stats sample = _currentSample;
|
||||
_currentSample = Stats();
|
||||
|
||||
auto now = duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch());
|
||||
auto now = duration_cast<microseconds>(system_clock::now().time_since_epoch());
|
||||
sample.endTime = now;
|
||||
_currentSample.startTime = now;
|
||||
|
||||
|
|
|
@ -36,11 +36,13 @@ public:
|
|||
SentTimeoutNAK,
|
||||
ReceivedTimeoutNAK,
|
||||
Retransmission,
|
||||
Duplicate
|
||||
Duplicate,
|
||||
|
||||
NumEvents
|
||||
};
|
||||
|
||||
// construct a vector for the events of the size of our Enum - default value is zero
|
||||
std::vector<int> events = std::vector<int>((int) Event::Duplicate + 1, 0);
|
||||
std::vector<int> events = std::vector<int>((int) Event::NumEvents, 0);
|
||||
|
||||
// packet counts and sizes
|
||||
int sentPackets { 0 };
|
||||
|
|
|
@ -15,6 +15,21 @@
|
|||
|
||||
using namespace udt;
|
||||
|
||||
std::unique_ptr<PacketList> PacketList::create(PacketType packetType, QByteArray extendedHeader,
|
||||
bool isReliable, bool isOrdered) {
|
||||
auto packetList = std::unique_ptr<PacketList>(new PacketList(packetType, extendedHeader,
|
||||
isReliable, isOrdered));
|
||||
packetList->open(WriteOnly);
|
||||
return packetList;
|
||||
}
|
||||
|
||||
std::unique_ptr<PacketList> PacketList::fromReceivedPackets(std::list<std::unique_ptr<Packet>>&& packets) {
|
||||
auto packetList = std::unique_ptr<PacketList>(new PacketList(PacketType::Unknown, QByteArray(), true, true));
|
||||
packetList->_packets = std::move(packets);
|
||||
packetList->open(ReadOnly);
|
||||
return packetList;
|
||||
}
|
||||
|
||||
PacketList::PacketList(PacketType packetType, QByteArray extendedHeader, bool isReliable, bool isOrdered) :
|
||||
_packetType(packetType),
|
||||
_isReliable(isReliable),
|
||||
|
@ -22,14 +37,15 @@ PacketList::PacketList(PacketType packetType, QByteArray extendedHeader, bool is
|
|||
_extendedHeader(extendedHeader)
|
||||
{
|
||||
Q_ASSERT_X(!(!_isReliable && _isOrdered), "PacketList", "Unreliable ordered PacketLists are not currently supported");
|
||||
QIODevice::open(WriteOnly);
|
||||
}
|
||||
|
||||
PacketList::PacketList(PacketList&& other) :
|
||||
_packetType(other._packetType),
|
||||
_packets(std::move(other._packets)),
|
||||
_packetType(other._packetType)
|
||||
_isReliable(other._isReliable),
|
||||
_isOrdered(other._isOrdered),
|
||||
_extendedHeader(std::move(other._extendedHeader))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PacketList::startSegment() {
|
||||
|
@ -66,12 +82,6 @@ size_t PacketList::getMessageSize() const {
|
|||
return totalBytes;
|
||||
}
|
||||
|
||||
std::unique_ptr<PacketList> PacketList::fromReceivedPackets(std::list<std::unique_ptr<Packet>>&& packets) {
|
||||
auto packetList = std::unique_ptr<PacketList>(new PacketList(PacketType::Unknown, QByteArray(), true, true));
|
||||
packetList->_packets = std::move(packets);
|
||||
return packetList;
|
||||
}
|
||||
|
||||
std::unique_ptr<Packet> PacketList::createPacket() {
|
||||
// use the static create method to create a new packet
|
||||
// If this packet list is supposed to be ordered then we consider this to be part of a message
|
||||
|
@ -94,6 +104,17 @@ std::unique_ptr<Packet> PacketList::createPacketWithExtendedHeader() {
|
|||
return packet;
|
||||
}
|
||||
|
||||
void PacketList::closeCurrentPacket(bool shouldSendEmpty) {
|
||||
if (shouldSendEmpty && !_currentPacket) {
|
||||
_currentPacket = createPacketWithExtendedHeader();
|
||||
}
|
||||
|
||||
if (_currentPacket) {
|
||||
// move the current packet to our list of packets
|
||||
_packets.push_back(std::move(_currentPacket));
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray PacketList::getMessage() {
|
||||
size_t sizeBytes = 0;
|
||||
|
||||
|
@ -191,14 +212,3 @@ qint64 PacketList::writeData(const char* data, qint64 maxSize) {
|
|||
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
void PacketList::closeCurrentPacket(bool shouldSendEmpty) {
|
||||
if (shouldSendEmpty && !_currentPacket) {
|
||||
_currentPacket = createPacketWithExtendedHeader();
|
||||
}
|
||||
|
||||
if (_currentPacket) {
|
||||
// move the current packet to our list of packets
|
||||
_packets.push_back(std::move(_currentPacket));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,13 +28,9 @@ class Packet;
|
|||
class PacketList : public QIODevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false);
|
||||
PacketList(PacketList&& other);
|
||||
|
||||
static std::unique_ptr<PacketList> create(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false);
|
||||
static std::unique_ptr<PacketList> fromReceivedPackets(std::list<std::unique_ptr<Packet>>&& packets);
|
||||
|
||||
virtual bool isSequential() const { return true; }
|
||||
|
||||
bool isReliable() const { return _isReliable; }
|
||||
bool isOrdered() const { return _isOrdered; }
|
||||
|
||||
|
@ -53,20 +49,28 @@ public:
|
|||
|
||||
QByteArray getMessage();
|
||||
|
||||
// QIODevice virtual functions
|
||||
virtual bool isSequential() const { return false; }
|
||||
virtual qint64 size() const { return getDataSize(); }
|
||||
|
||||
template<typename T> qint64 readPrimitive(T* data);
|
||||
template<typename T> qint64 writePrimitive(const T& data);
|
||||
std::list<std::unique_ptr<Packet>> _packets;
|
||||
|
||||
protected:
|
||||
virtual qint64 writeData(const char* data, qint64 maxSize);
|
||||
virtual qint64 readData(char* data, qint64 maxSize) { return 0; }
|
||||
PacketType _packetType;
|
||||
PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false);
|
||||
PacketList(PacketList&& other);
|
||||
|
||||
virtual qint64 writeData(const char* data, qint64 maxSize);
|
||||
// Not implemented, added an assert so that it doesn't get used by accident
|
||||
virtual qint64 readData(char* data, qint64 maxSize) { Q_ASSERT(false); return 0; }
|
||||
|
||||
PacketType _packetType;
|
||||
std::list<std::unique_ptr<Packet>> _packets;
|
||||
|
||||
private:
|
||||
friend class ::LimitedNodeList;
|
||||
friend class Socket;
|
||||
friend class SendQueue;
|
||||
friend class NLPacketList;
|
||||
friend class Socket;
|
||||
|
||||
PacketList(const PacketList& other) = delete;
|
||||
PacketList& operator=(const PacketList& other) = delete;
|
||||
|
@ -91,12 +95,12 @@ private:
|
|||
|
||||
template <typename T> qint64 PacketList::readPrimitive(T* data) {
|
||||
static_assert(!std::is_pointer<T>::value, "T must not be a pointer");
|
||||
return QIODevice::read(reinterpret_cast<char*>(data), sizeof(T));
|
||||
return read(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T> qint64 PacketList::writePrimitive(const T& data) {
|
||||
static_assert(!std::is_pointer<T>::value, "T must not be a pointer");
|
||||
return QIODevice::write(reinterpret_cast<const char*>(&data), sizeof(T));
|
||||
return write(reinterpret_cast<const char*>(&data), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> std::unique_ptr<T> PacketList::takeFront() {
|
||||
|
|
|
@ -325,6 +325,16 @@ ConnectionStats::Stats Socket::sampleStatsForConnection(const HifiSockAddr& dest
|
|||
}
|
||||
}
|
||||
|
||||
Socket::StatsVector Socket::sampleStatsForAllConnections() {
|
||||
StatsVector result;
|
||||
result.reserve(_connectionsHash.size());
|
||||
for (const auto& connectionPair : _connectionsHash) {
|
||||
result.emplace_back(connectionPair.first, connectionPair.second->sampleStats());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::vector<HifiSockAddr> Socket::getConnectionSockAddrs() {
|
||||
std::vector<HifiSockAddr> addr;
|
||||
addr.reserve(_connectionsHash.size());
|
||||
|
|
|
@ -46,6 +46,8 @@ using PacketListHandler = std::function<void(std::unique_ptr<PacketList>)>;
|
|||
class Socket : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using StatsVector = std::vector<std::pair<HifiSockAddr, ConnectionStats::Stats>>;
|
||||
|
||||
Socket(QObject* object = 0);
|
||||
|
||||
quint16 localPort() const { return _udpSocket.localPort(); }
|
||||
|
@ -71,6 +73,8 @@ public:
|
|||
void setCongestionControlFactory(std::unique_ptr<CongestionControlVirtualFactory> ccFactory);
|
||||
|
||||
void messageReceived(std::unique_ptr<PacketList> packetList);
|
||||
|
||||
StatsVector sampleStatsForAllConnections();
|
||||
|
||||
public slots:
|
||||
void cleanupConnection(HifiSockAddr sockAddr);
|
||||
|
@ -86,6 +90,7 @@ private:
|
|||
|
||||
// privatized methods used by UDTTest - they are private since they must be called on the Socket thread
|
||||
ConnectionStats::Stats sampleStatsForConnection(const HifiSockAddr& destination);
|
||||
|
||||
std::vector<HifiSockAddr> getConnectionSockAddrs();
|
||||
void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot);
|
||||
|
||||
|
|
|
@ -176,6 +176,14 @@ void AnimDebugDraw::removePoses(const std::string& key) {
|
|||
_poses.erase(key);
|
||||
}
|
||||
|
||||
void AnimDebugDraw::addPose(const std::string& key, const AnimPose& pose, const AnimPose& rootPose) {
|
||||
_singlePoses[key] = SinglePoseInfo(pose, rootPose);
|
||||
}
|
||||
|
||||
void AnimDebugDraw::removePose(const std::string& key) {
|
||||
_singlePoses.erase(key);
|
||||
}
|
||||
|
||||
static const uint32_t red = toRGBA(255, 0, 0, 255);
|
||||
static const uint32_t green = toRGBA(0, 255, 0, 255);
|
||||
static const uint32_t blue = toRGBA(0, 0, 255, 255);
|
||||
|
@ -333,6 +341,7 @@ void AnimDebugDraw::update() {
|
|||
const size_t VERTICES_PER_LINK = 8 * 2;
|
||||
|
||||
const float BONE_RADIUS = 0.01f; // 1 cm
|
||||
const float POSE_RADIUS = 0.1f; // 10 cm
|
||||
|
||||
// figure out how many verts we will need.
|
||||
int numVerts = 0;
|
||||
|
@ -371,6 +380,8 @@ void AnimDebugDraw::update() {
|
|||
}
|
||||
}
|
||||
|
||||
numVerts += _singlePoses.size() * VERTICES_PER_BONE;
|
||||
|
||||
data._vertexBuffer->resize(sizeof(Vertex) * numVerts);
|
||||
Vertex* verts = (Vertex*)data._vertexBuffer->editData();
|
||||
Vertex* v = verts;
|
||||
|
@ -475,6 +486,13 @@ void AnimDebugDraw::update() {
|
|||
}
|
||||
}
|
||||
|
||||
for (auto& iter : _singlePoses) {
|
||||
AnimPose pose = std::get<0>(iter.second);
|
||||
AnimPose rootPose = std::get<1>(iter.second);
|
||||
const float radius = POSE_RADIUS / (pose.scale.x * rootPose.scale.x);
|
||||
addBone(rootPose, pose, radius, v);
|
||||
}
|
||||
|
||||
assert(numVerts == (v - verts));
|
||||
|
||||
data._indexBuffer->resize(sizeof(uint16_t) * numVerts);
|
||||
|
|
|
@ -27,15 +27,22 @@ public:
|
|||
AnimDebugDraw();
|
||||
~AnimDebugDraw();
|
||||
|
||||
// draw a skeleton bind pose
|
||||
void addSkeleton(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPose& rootPose, const glm::vec4& color);
|
||||
void removeSkeleton(const std::string& key);
|
||||
|
||||
// draw the interal poses for a specific animNode
|
||||
void addAnimNode(const std::string& key, AnimNode::ConstPointer animNode, const AnimPose& rootPose, const glm::vec4& color);
|
||||
void removeAnimNode(const std::string& key);
|
||||
|
||||
// draw a set of poses with a skeleton
|
||||
void addPoses(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPoseVec& poses, const AnimPose& rootPose, const glm::vec4& color);
|
||||
void removePoses(const std::string& key);
|
||||
|
||||
// draw a single pose
|
||||
void addPose(const std::string& key, const AnimPose& rootPose, const AnimPose& pose);
|
||||
void removePose(const std::string& key);
|
||||
|
||||
void update();
|
||||
|
||||
protected:
|
||||
|
@ -48,10 +55,12 @@ protected:
|
|||
typedef std::tuple<AnimSkeleton::ConstPointer, AnimPose, glm::vec4> SkeletonInfo;
|
||||
typedef std::tuple<AnimNode::ConstPointer, AnimPose, glm::vec4> AnimNodeInfo;
|
||||
typedef std::tuple<AnimSkeleton::ConstPointer, AnimPoseVec, AnimPose, glm::vec4> PosesInfo;
|
||||
typedef std::tuple<AnimPose, AnimPose> SinglePoseInfo;
|
||||
|
||||
std::unordered_map<std::string, SkeletonInfo> _skeletons;
|
||||
std::unordered_map<std::string, AnimNodeInfo> _animNodes;
|
||||
std::unordered_map<std::string, PosesInfo> _poses;
|
||||
std::unordered_map<std::string, SinglePoseInfo> _singlePoses;
|
||||
|
||||
// no copies
|
||||
AnimDebugDraw(const AnimDebugDraw&) = delete;
|
||||
|
|
|
@ -68,6 +68,7 @@ void ScriptCache::scriptDownloaded() {
|
|||
qCDebug(scriptengine) << "Done downloading script at:" << url.toString();
|
||||
|
||||
foreach(ScriptUser* user, scriptUsers) {
|
||||
// FIXME - I sometimes get a crash deep below here inside of Qt while evaluating the script
|
||||
user->scriptContentsAvailable(url, _scriptCache[url]);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -81,7 +81,7 @@ void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputCon
|
|||
}
|
||||
|
||||
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
|
||||
AbstractControllerScriptingInterface* controllerScriptingInterface) :
|
||||
AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) :
|
||||
|
||||
_scriptContents(scriptContents),
|
||||
_isFinished(false),
|
||||
|
@ -95,6 +95,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
|
|||
_avatarSound(NULL),
|
||||
_numAvatarSoundSentBytes(0),
|
||||
_controllerScriptingInterface(controllerScriptingInterface),
|
||||
_wantSignals(wantSignals),
|
||||
_avatarData(NULL),
|
||||
_scriptName(),
|
||||
_fileNameString(fileNameString),
|
||||
|
@ -260,6 +261,20 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents, const QStrin
|
|||
return true;
|
||||
}
|
||||
|
||||
void ScriptEngine::callScriptMethod(QString methodName, QScriptValue script, QScriptValueList args) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this,
|
||||
"callScriptMethod",
|
||||
Q_ARG(QString, methodName),
|
||||
Q_ARG(QScriptValue, script),
|
||||
Q_ARG(QScriptValueList, args));
|
||||
return;
|
||||
}
|
||||
|
||||
//qDebug() << "About to call " << methodName << "() current thread : " << QThread::currentThread() << "engine thread : " << thread();
|
||||
script.property(methodName).call(script, args);
|
||||
}
|
||||
|
||||
void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
|
||||
if (_isRunning) {
|
||||
return;
|
||||
|
@ -285,10 +300,14 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
|
|||
qCDebug(scriptengine) << "ScriptEngine loading file:" << _fileNameString;
|
||||
QTextStream in(&scriptFile);
|
||||
_scriptContents = in.readAll();
|
||||
emit scriptLoaded(_fileNameString);
|
||||
if (_wantSignals) {
|
||||
emit scriptLoaded(_fileNameString);
|
||||
}
|
||||
} else {
|
||||
qCDebug(scriptengine) << "ERROR Loading file:" << _fileNameString << "line:" << __LINE__;
|
||||
emit errorLoadingScript(_fileNameString);
|
||||
if (_wantSignals) {
|
||||
emit errorLoadingScript(_fileNameString);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool isPending;
|
||||
|
@ -300,12 +319,16 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
|
|||
|
||||
void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scriptContents) {
|
||||
_scriptContents = scriptContents;
|
||||
emit scriptLoaded(_fileNameString);
|
||||
if (_wantSignals) {
|
||||
emit scriptLoaded(_fileNameString);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::errorInLoadingScript(const QUrl& url) {
|
||||
qCDebug(scriptengine) << "ERROR Loading file:" << url.toString() << "line:" << __LINE__;
|
||||
emit errorLoadingScript(_fileNameString); // ??
|
||||
if (_wantSignals) {
|
||||
emit errorLoadingScript(_fileNameString); // ??
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::init() {
|
||||
|
@ -510,7 +533,9 @@ void ScriptEngine::evaluate() {
|
|||
if (hasUncaughtException()) {
|
||||
int line = uncaughtExceptionLineNumber();
|
||||
qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString();
|
||||
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString());
|
||||
if (_wantSignals) {
|
||||
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString());
|
||||
}
|
||||
clearExceptions();
|
||||
}
|
||||
}
|
||||
|
@ -527,7 +552,9 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN
|
|||
qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString();
|
||||
}
|
||||
_evaluatesPending--;
|
||||
emit evaluationFinished(result, hasUncaughtException());
|
||||
if (_wantSignals) {
|
||||
emit evaluationFinished(result, hasUncaughtException());
|
||||
}
|
||||
clearExceptions();
|
||||
return result;
|
||||
}
|
||||
|
@ -553,7 +580,9 @@ void ScriptEngine::run() {
|
|||
}
|
||||
_isRunning = true;
|
||||
_isFinished = false;
|
||||
emit runningStateChanged();
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
}
|
||||
|
||||
QScriptValue result = evaluate(_scriptContents);
|
||||
|
||||
|
@ -700,19 +729,25 @@ void ScriptEngine::run() {
|
|||
if (hasUncaughtException()) {
|
||||
int line = uncaughtExceptionLineNumber();
|
||||
qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString();
|
||||
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString());
|
||||
if (_wantSignals) {
|
||||
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString());
|
||||
}
|
||||
clearExceptions();
|
||||
}
|
||||
|
||||
if (!_isFinished) {
|
||||
emit update(deltaTime);
|
||||
if (_wantSignals) {
|
||||
emit update(deltaTime);
|
||||
}
|
||||
}
|
||||
lastUpdate = now;
|
||||
|
||||
}
|
||||
|
||||
stopAllTimers(); // make sure all our timers are stopped if the script is ending
|
||||
emit scriptEnding();
|
||||
if (_wantSignals) {
|
||||
emit scriptEnding();
|
||||
}
|
||||
|
||||
// kill the avatar identity timer
|
||||
delete _avatarIdentityTimer;
|
||||
|
@ -733,12 +768,15 @@ void ScriptEngine::run() {
|
|||
}
|
||||
}
|
||||
|
||||
emit finished(_fileNameString);
|
||||
if (_wantSignals) {
|
||||
emit finished(_fileNameString);
|
||||
}
|
||||
|
||||
_isRunning = false;
|
||||
emit runningStateChanged();
|
||||
|
||||
emit doneRunning();
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
emit doneRunning();
|
||||
}
|
||||
|
||||
_doneRunningThisScript = true;
|
||||
}
|
||||
|
@ -757,7 +795,9 @@ void ScriptEngine::stopAllTimers() {
|
|||
void ScriptEngine::stop() {
|
||||
if (!_isFinished) {
|
||||
_isFinished = true;
|
||||
emit runningStateChanged();
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -845,7 +885,9 @@ QUrl ScriptEngine::resolvePath(const QString& include) const {
|
|||
}
|
||||
|
||||
void ScriptEngine::print(const QString& message) {
|
||||
emit printedMessage(message);
|
||||
if (_wantSignals) {
|
||||
emit printedMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
// If a callback is specified, the included files will be loaded asynchronously and the callback will be called
|
||||
|
@ -929,9 +971,13 @@ void ScriptEngine::load(const QString& loadFile) {
|
|||
if (_isReloading) {
|
||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||
scriptCache->deleteScript(url.toString());
|
||||
emit reloadScript(url.toString(), false);
|
||||
if (_wantSignals) {
|
||||
emit reloadScript(url.toString(), false);
|
||||
}
|
||||
} else {
|
||||
emit loadScript(url.toString(), false);
|
||||
if (_wantSignals) {
|
||||
emit loadScript(url.toString(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,8 @@ class ScriptEngine : public QScriptEngine, public ScriptUser {
|
|||
public:
|
||||
ScriptEngine(const QString& scriptContents = NO_SCRIPT,
|
||||
const QString& fileNameString = QString(""),
|
||||
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
||||
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL,
|
||||
bool wantSignals = true);
|
||||
|
||||
~ScriptEngine();
|
||||
|
||||
|
@ -64,6 +65,8 @@ public:
|
|||
int numArguments = -1);
|
||||
|
||||
Q_INVOKABLE void setIsAvatar(bool isAvatar);
|
||||
Q_INVOKABLE void callScriptMethod(QString methodName, QScriptValue script, QScriptValueList args);
|
||||
|
||||
bool isAvatar() const { return _isAvatar; }
|
||||
|
||||
void setAvatarData(AvatarData* avatarData, const QString& objectName);
|
||||
|
@ -154,6 +157,7 @@ protected:
|
|||
int _numAvatarSoundSentBytes;
|
||||
bool _isAgent = false;
|
||||
QSet<QUrl> _includedURLs;
|
||||
bool _wantSignals = true;
|
||||
|
||||
private:
|
||||
void stopAllTimers();
|
||||
|
|
|
@ -26,7 +26,8 @@ static int quatMetaTypeId = qRegisterMetaType<glm::quat>();
|
|||
static int xColorMetaTypeId = qRegisterMetaType<xColor>();
|
||||
static int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
|
||||
static int collisionMetaTypeId = qRegisterMetaType<Collision>();
|
||||
static int qMapURLStringMetaTypeId = qRegisterMetaType<QMap<QUrl,QString>>();
|
||||
static int qMapURLStringMetaTypeId = qRegisterMetaType<QMap<QUrl, QString>>();
|
||||
static int qScriptValueListMetaTypeId = qRegisterMetaType<QScriptValueList>("QScriptValueList");
|
||||
|
||||
void registerMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
"jointName": "LeftHand",
|
||||
"positionVar": "leftHandPosition",
|
||||
"rotationVar": "leftHandRotation"
|
||||
},
|
||||
{
|
||||
"jointName": "Head",
|
||||
"positionVar": "headPosition",
|
||||
"rotationVar": "headRotation"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -267,9 +267,7 @@ void UDTTest::sendPacket() {
|
|||
|
||||
if (call++ % refillCount == 0) {
|
||||
// construct a reliable and ordered packet list
|
||||
auto packetList = std::unique_ptr<udt::PacketList>({
|
||||
new udt::PacketList(PacketType::BulkAvatarData, QByteArray(), true, true)
|
||||
});
|
||||
auto packetList = udt::PacketList::create(PacketType::BulkAvatarData, QByteArray(), true, true);
|
||||
|
||||
// fill the packet list with random data according to the constant seed (so receiver can verify)
|
||||
for (int i = 0; i < messageSizePackets; ++i) {
|
||||
|
|
Loading…
Reference in a new issue