mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 20:36:49 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels
This commit is contained in:
commit
e66cfa8422
10 changed files with 130 additions and 128 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include <QtCore/QDateTime>
|
#include <QtCore/QDateTime>
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <Logging.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
|
@ -27,7 +28,7 @@
|
||||||
|
|
||||||
const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
|
const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
|
||||||
|
|
||||||
const unsigned int AVATAR_DATA_SEND_INTERVAL_USECS = (1 / 60.0) * 1000 * 1000;
|
const unsigned int AVATAR_DATA_SEND_INTERVAL_MSECS = (1.0f / 60.0f) * 1000;
|
||||||
|
|
||||||
AvatarMixer::AvatarMixer(const QByteArray& packet) :
|
AvatarMixer::AvatarMixer(const QByteArray& packet) :
|
||||||
ThreadedAssignment(packet),
|
ThreadedAssignment(packet),
|
||||||
|
@ -54,43 +55,97 @@ const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f;
|
||||||
// NOTE: some additional optimizations to consider.
|
// NOTE: some additional optimizations to consider.
|
||||||
// 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
|
// 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
|
||||||
// if the avatar is not in view or in the keyhole.
|
// if the avatar is not in view or in the keyhole.
|
||||||
// 2) after culling for view frustum, sort order the avatars by distance, send the closest ones first.
|
|
||||||
// 3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to
|
|
||||||
// determine which avatars are included in the packet stream
|
|
||||||
// 4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful).
|
|
||||||
void AvatarMixer::broadcastAvatarData() {
|
void AvatarMixer::broadcastAvatarData() {
|
||||||
|
|
||||||
|
int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp;
|
||||||
|
|
||||||
|
++_numStatFrames;
|
||||||
|
|
||||||
|
const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f;
|
||||||
|
const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f;
|
||||||
|
|
||||||
|
const float RATIO_BACK_OFF = 0.02f;
|
||||||
|
|
||||||
|
const int TRAILING_AVERAGE_FRAMES = 100;
|
||||||
|
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
|
||||||
|
|
||||||
|
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES;
|
||||||
|
const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
|
||||||
|
|
||||||
|
_trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio)
|
||||||
|
+ (idleTime * CURRENT_FRAME_RATIO / (float) AVATAR_DATA_SEND_INTERVAL_MSECS);
|
||||||
|
|
||||||
|
float lastCutoffRatio = _performanceThrottlingRatio;
|
||||||
|
bool hasRatioChanged = false;
|
||||||
|
|
||||||
|
if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) {
|
||||||
|
if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) {
|
||||||
|
// we're struggling - change our min required loudness to reduce some load
|
||||||
|
_performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio));
|
||||||
|
|
||||||
|
qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was"
|
||||||
|
<< lastCutoffRatio << "and is now" << _performanceThrottlingRatio;
|
||||||
|
hasRatioChanged = true;
|
||||||
|
} else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) {
|
||||||
|
// we've recovered and can back off the required loudness
|
||||||
|
_performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF;
|
||||||
|
|
||||||
|
if (_performanceThrottlingRatio < 0) {
|
||||||
|
_performanceThrottlingRatio = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was"
|
||||||
|
<< lastCutoffRatio << "and is now" << _performanceThrottlingRatio;
|
||||||
|
hasRatioChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasRatioChanged) {
|
||||||
|
framesSinceCutoffEvent = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasRatioChanged) {
|
||||||
|
++framesSinceCutoffEvent;
|
||||||
|
}
|
||||||
|
|
||||||
static QByteArray mixedAvatarByteArray;
|
static QByteArray mixedAvatarByteArray;
|
||||||
|
|
||||||
int numPacketHeaderBytes = populatePacketHeader(mixedAvatarByteArray, PacketTypeBulkAvatarData);
|
int numPacketHeaderBytes = populatePacketHeader(mixedAvatarByteArray, PacketTypeBulkAvatarData);
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
|
||||||
|
AvatarMixerClientData* nodeData = NULL;
|
||||||
|
AvatarMixerClientData* otherNodeData = NULL;
|
||||||
|
|
||||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||||
if (node->getLinkedData() && node->getType() == NodeType::Agent && node->getActiveSocket()) {
|
if (node->getLinkedData() && node->getType() == NodeType::Agent && node->getActiveSocket()
|
||||||
|
&& (nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData()))->getMutex().tryLock()) {
|
||||||
++_sumListeners;
|
++_sumListeners;
|
||||||
|
|
||||||
// reset packet pointers for this node
|
// reset packet pointers for this node
|
||||||
mixedAvatarByteArray.resize(numPacketHeaderBytes);
|
mixedAvatarByteArray.resize(numPacketHeaderBytes);
|
||||||
|
|
||||||
AvatarMixerClientData* myData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
|
AvatarData& avatar = nodeData->getAvatar();
|
||||||
AvatarData& avatar = myData->getAvatar();
|
|
||||||
glm::vec3 myPosition = avatar.getPosition();
|
glm::vec3 myPosition = avatar.getPosition();
|
||||||
|
|
||||||
// this is an AGENT we have received head data from
|
// this is an AGENT we have received head data from
|
||||||
// send back a packet with other active node data to this node
|
// send back a packet with other active node data to this node
|
||||||
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
|
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
|
||||||
if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID()) {
|
if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID()
|
||||||
|
&& (otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData()))->getMutex().tryLock()) {
|
||||||
|
|
||||||
AvatarMixerClientData* otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
|
AvatarMixerClientData* otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
|
||||||
AvatarData& otherAvatar = otherNodeData->getAvatar();
|
AvatarData& otherAvatar = otherNodeData->getAvatar();
|
||||||
glm::vec3 otherPosition = otherAvatar.getPosition();
|
glm::vec3 otherPosition = otherAvatar.getPosition();
|
||||||
|
|
||||||
float distanceToAvatar = glm::length(myPosition - otherPosition);
|
float distanceToAvatar = glm::length(myPosition - otherPosition);
|
||||||
// The full rate distance is the distance at which EVERY update will be sent for this avatar
|
// The full rate distance is the distance at which EVERY update will be sent for this avatar
|
||||||
// at a distance of twice the full rate distance, there will be a 50% chance of sending this avatar's update
|
// at a distance of twice the full rate distance, there will be a 50% chance of sending this avatar's update
|
||||||
const float FULL_RATE_DISTANCE = 2.f;
|
const float FULL_RATE_DISTANCE = 2.f;
|
||||||
|
|
||||||
// Decide whether to send this avatar's data based on it's distance from us
|
// Decide whether to send this avatar's data based on it's distance from us
|
||||||
if ((distanceToAvatar == 0.f) || (randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)
|
if ((_performanceThrottlingRatio == 0 || randFloat() < (1.0f - _performanceThrottlingRatio))
|
||||||
* (1 - _performanceThrottlingRatio)) {
|
&& (distanceToAvatar == 0.f || randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)) {
|
||||||
QByteArray avatarByteArray;
|
QByteArray avatarByteArray;
|
||||||
avatarByteArray.append(otherNode->getUUID().toRfc4122());
|
avatarByteArray.append(otherNode->getUUID().toRfc4122());
|
||||||
avatarByteArray.append(otherAvatar.toByteArray());
|
avatarByteArray.append(otherAvatar.toByteArray());
|
||||||
|
@ -107,7 +162,7 @@ void AvatarMixer::broadcastAvatarData() {
|
||||||
|
|
||||||
// if the receiving avatar has just connected make sure we send out the mesh and billboard
|
// if the receiving avatar has just connected make sure we send out the mesh and billboard
|
||||||
// for this avatar (assuming they exist)
|
// for this avatar (assuming they exist)
|
||||||
bool forceSend = !myData->checkAndSetHasReceivedFirstPackets();
|
bool forceSend = !nodeData->checkAndSetHasReceivedFirstPackets();
|
||||||
|
|
||||||
// we will also force a send of billboard or identity packet
|
// we will also force a send of billboard or identity packet
|
||||||
// if either has changed in the last frame
|
// if either has changed in the last frame
|
||||||
|
@ -140,10 +195,14 @@ void AvatarMixer::broadcastAvatarData() {
|
||||||
++_sumIdentityPackets;
|
++_sumIdentityPackets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
otherNodeData->getMutex().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeList->writeDatagram(mixedAvatarByteArray, node);
|
nodeList->writeDatagram(mixedAvatarByteArray, node);
|
||||||
|
|
||||||
|
nodeData->getMutex().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +246,7 @@ void AvatarMixer::readPendingDatagrams() {
|
||||||
|
|
||||||
// parse the identity packet and update the change timestamp if appropriate
|
// parse the identity packet and update the change timestamp if appropriate
|
||||||
if (avatar.hasIdentityChangedAfterParsing(receivedPacket)) {
|
if (avatar.hasIdentityChangedAfterParsing(receivedPacket)) {
|
||||||
|
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||||
nodeData->setIdentityChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
nodeData->setIdentityChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,6 +263,7 @@ void AvatarMixer::readPendingDatagrams() {
|
||||||
|
|
||||||
// parse the billboard packet and update the change timestamp if appropriate
|
// parse the billboard packet and update the change timestamp if appropriate
|
||||||
if (avatar.hasBillboardChangedAfterParsing(receivedPacket)) {
|
if (avatar.hasBillboardChangedAfterParsing(receivedPacket)) {
|
||||||
|
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||||
nodeData->setBillboardChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
nodeData->setBillboardChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,80 +309,18 @@ void AvatarMixer::run() {
|
||||||
|
|
||||||
nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
|
nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
|
||||||
|
|
||||||
int nextFrame = 0;
|
// create a thead for broadcast of avatar data
|
||||||
timeval startTime;
|
QThread* broadcastThread = new QThread(this);
|
||||||
|
|
||||||
gettimeofday(&startTime, NULL);
|
// setup the timer that will be fired on the broadcast thread
|
||||||
|
QTimer* broadcastTimer = new QTimer();
|
||||||
|
broadcastTimer->setInterval(AVATAR_DATA_SEND_INTERVAL_MSECS);
|
||||||
|
broadcastTimer->moveToThread(broadcastThread);
|
||||||
|
|
||||||
int usecToSleep = AVATAR_DATA_SEND_INTERVAL_USECS;
|
// connect appropriate signals and slots
|
||||||
|
connect(broadcastTimer, &QTimer::timeout, this, &AvatarMixer::broadcastAvatarData, Qt::DirectConnection);
|
||||||
|
connect(broadcastThread, SIGNAL(started()), broadcastTimer, SLOT(start()));
|
||||||
|
|
||||||
const int TRAILING_AVERAGE_FRAMES = 100;
|
// start the broadcastThread
|
||||||
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
|
broadcastThread->start();
|
||||||
|
|
||||||
while (!_isFinished) {
|
|
||||||
|
|
||||||
++_numStatFrames;
|
|
||||||
|
|
||||||
const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f;
|
|
||||||
const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f;
|
|
||||||
|
|
||||||
const float RATIO_BACK_OFF = 0.02f;
|
|
||||||
|
|
||||||
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES;
|
|
||||||
const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
|
|
||||||
|
|
||||||
if (usecToSleep < 0) {
|
|
||||||
usecToSleep = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio)
|
|
||||||
+ (usecToSleep * CURRENT_FRAME_RATIO / (float) AVATAR_DATA_SEND_INTERVAL_USECS);
|
|
||||||
|
|
||||||
float lastCutoffRatio = _performanceThrottlingRatio;
|
|
||||||
bool hasRatioChanged = false;
|
|
||||||
|
|
||||||
if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) {
|
|
||||||
if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) {
|
|
||||||
// we're struggling - change our min required loudness to reduce some load
|
|
||||||
_performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio));
|
|
||||||
|
|
||||||
qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was"
|
|
||||||
<< lastCutoffRatio << "and is now" << _performanceThrottlingRatio;
|
|
||||||
hasRatioChanged = true;
|
|
||||||
} else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) {
|
|
||||||
// we've recovered and can back off the required loudness
|
|
||||||
_performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF;
|
|
||||||
|
|
||||||
if (_performanceThrottlingRatio < 0) {
|
|
||||||
_performanceThrottlingRatio = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was"
|
|
||||||
<< lastCutoffRatio << "and is now" << _performanceThrottlingRatio;
|
|
||||||
hasRatioChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasRatioChanged) {
|
|
||||||
framesSinceCutoffEvent = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasRatioChanged) {
|
|
||||||
++framesSinceCutoffEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcastAvatarData();
|
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
|
|
||||||
if (_isFinished) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
usecToSleep = usecTimestamp(&startTime) + (++nextFrame * AVATAR_DATA_SEND_INTERVAL_USECS) - usecTimestampNow();
|
|
||||||
|
|
||||||
if (usecToSleep > 0) {
|
|
||||||
usleep(usecToSleep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,5 @@
|
||||||
Script.include("lookWithTouch.js");
|
Script.include("lookWithTouch.js");
|
||||||
Script.include("editVoxels.js");
|
Script.include("editVoxels.js");
|
||||||
Script.include("selectAudioDevice.js");
|
Script.include("selectAudioDevice.js");
|
||||||
Script.include("hydraMove.js");
|
Script.include("hydraMove.js");
|
||||||
|
Script.include("inspect.js");
|
|
@ -9,6 +9,7 @@
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
|
var startedTouching = false;
|
||||||
var lastX = 0;
|
var lastX = 0;
|
||||||
var lastY = 0;
|
var lastY = 0;
|
||||||
var yawFromMouse = 0;
|
var yawFromMouse = 0;
|
||||||
|
@ -21,12 +22,14 @@ function touchBeginEvent(event) {
|
||||||
}
|
}
|
||||||
lastX = event.x;
|
lastX = event.x;
|
||||||
lastY = event.y;
|
lastY = event.y;
|
||||||
|
startedTouching = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function touchEndEvent(event) {
|
function touchEndEvent(event) {
|
||||||
if (wantDebugging) {
|
if (wantDebugging) {
|
||||||
print("touchEndEvent event.x,y=" + event.x + ", " + event.y);
|
print("touchEndEvent event.x,y=" + event.x + ", " + event.y);
|
||||||
}
|
}
|
||||||
|
startedTouching = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function touchUpdateEvent(event) {
|
function touchUpdateEvent(event) {
|
||||||
|
@ -44,24 +47,26 @@ function touchUpdateEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
// rotate body yaw for yaw received from mouse
|
if (startedTouching) {
|
||||||
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollRadians(0, yawFromMouse, 0));
|
// rotate body yaw for yaw received from mouse
|
||||||
if (wantDebugging) {
|
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollRadians(0, yawFromMouse, 0));
|
||||||
print("changing orientation"
|
if (wantDebugging) {
|
||||||
+ " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + ","
|
print("changing orientation"
|
||||||
+ MyAvatar.orientation.z + "," + MyAvatar.orientation.w
|
+ " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + ","
|
||||||
+ " newOrientation="+newOrientation.x + "," + newOrientation.y + "," + newOrientation.z + "," + newOrientation.w);
|
+ MyAvatar.orientation.z + "," + MyAvatar.orientation.w
|
||||||
}
|
+ " newOrientation="+newOrientation.x + "," + newOrientation.y + "," + newOrientation.z + "," + newOrientation.w);
|
||||||
MyAvatar.orientation = newOrientation;
|
}
|
||||||
yawFromMouse = 0;
|
MyAvatar.orientation = newOrientation;
|
||||||
|
yawFromMouse = 0;
|
||||||
|
|
||||||
// apply pitch from mouse
|
// apply pitch from mouse
|
||||||
var newPitch = MyAvatar.headPitch + pitchFromMouse;
|
var newPitch = MyAvatar.headPitch + pitchFromMouse;
|
||||||
if (wantDebugging) {
|
if (wantDebugging) {
|
||||||
print("changing pitch [old]MyAvatar.headPitch="+MyAvatar.headPitch+ " newPitch="+newPitch);
|
print("changing pitch [old]MyAvatar.headPitch="+MyAvatar.headPitch+ " newPitch="+newPitch);
|
||||||
|
}
|
||||||
|
MyAvatar.headPitch = newPitch;
|
||||||
|
pitchFromMouse = 0;
|
||||||
}
|
}
|
||||||
MyAvatar.headPitch = newPitch;
|
|
||||||
pitchFromMouse = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the mouse events to our functions
|
// Map the mouse events to our functions
|
||||||
|
@ -77,10 +82,6 @@ function scriptEnding() {
|
||||||
Controller.releaseTouchEvents();
|
Controller.releaseTouchEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
MyAvatar.bodyYaw = 0;
|
|
||||||
MyAvatar.bodyPitch = 0;
|
|
||||||
MyAvatar.bodyRoll = 0;
|
|
||||||
|
|
||||||
// would be nice to change to update
|
// would be nice to change to update
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
|
|
@ -235,7 +235,6 @@ void ScriptEngine::init() {
|
||||||
// let the VoxelPacketSender know how frequently we plan to call it
|
// let the VoxelPacketSender know how frequently we plan to call it
|
||||||
_voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS);
|
_voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS);
|
||||||
_particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS);
|
_particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
||||||
|
|
|
@ -8,6 +8,12 @@
|
||||||
|
|
||||||
#include "NodeData.h"
|
#include "NodeData.h"
|
||||||
|
|
||||||
|
NodeData::NodeData() :
|
||||||
|
_mutex()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
NodeData::~NodeData() {
|
NodeData::~NodeData() {
|
||||||
|
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef hifi_NodeData_h
|
#ifndef hifi_NodeData_h
|
||||||
#define hifi_NodeData_h
|
#define hifi_NodeData_h
|
||||||
|
|
||||||
|
#include <QtCore/QMutex>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
class Node;
|
class Node;
|
||||||
|
@ -16,9 +17,14 @@ class Node;
|
||||||
class NodeData : public QObject {
|
class NodeData : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
NodeData();
|
||||||
virtual ~NodeData() = 0;
|
virtual ~NodeData() = 0;
|
||||||
virtual int parseData(const QByteArray& packet) = 0;
|
virtual int parseData(const QByteArray& packet) = 0;
|
||||||
|
|
||||||
|
QMutex& getMutex() { return _mutex; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex _mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -171,8 +171,13 @@ qint64 NodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& d
|
||||||
++_numCollectedPackets;
|
++_numCollectedPackets;
|
||||||
_numCollectedBytes += datagram.size();
|
_numCollectedBytes += datagram.size();
|
||||||
|
|
||||||
return _nodeSocket.writeDatagram(datagramCopy, destinationSockAddr.getAddress(), destinationSockAddr.getPort());
|
qint64 bytesWritten = _nodeSocket.writeDatagram(datagramCopy, destinationSockAddr.getAddress(), destinationSockAddr.getPort());
|
||||||
|
|
||||||
|
if (bytesWritten < 0) {
|
||||||
|
qDebug() << "ERROR in writeDatagram:" << _nodeSocket.error() << "-" << _nodeSocket.errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 NodeList::writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
qint64 NodeList::writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
||||||
|
@ -312,6 +317,8 @@ int NodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode
|
||||||
linkedDataCreateCallback(matchingNode.data());
|
linkedDataCreateCallback(matchingNode.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMutexLocker linkedDataLocker(&matchingNode->getLinkedData()->getMutex());
|
||||||
|
|
||||||
return matchingNode->getLinkedData()->parseData(packet);
|
return matchingNode->getLinkedData()->parseData(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,9 +420,8 @@ void NodeList::sendSTUNRequest() {
|
||||||
|
|
||||||
// transaction ID (random 12-byte unsigned integer)
|
// transaction ID (random 12-byte unsigned integer)
|
||||||
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
||||||
unsigned char transactionID[NUM_TRANSACTION_ID_BYTES];
|
QUuid randomUUID = QUuid::createUuid();
|
||||||
loadRandomIdentifier(transactionID, NUM_TRANSACTION_ID_BYTES);
|
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
|
||||||
memcpy(stunRequestPacket + packetIndex, &transactionID, sizeof(transactionID));
|
|
||||||
|
|
||||||
// lookup the IP for the STUN server
|
// lookup the IP for the STUN server
|
||||||
static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
|
static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
|
||||||
|
|
|
@ -206,15 +206,6 @@ bool isInEnvironment(const char* environment) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadRandomIdentifier(unsigned char* identifierBuffer, int numBytes) {
|
|
||||||
// seed the the random number generator
|
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
for (int i = 0; i < numBytes; i++) {
|
|
||||||
identifierBuffer[i] = rand() % 256;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Function: getCmdOption()
|
// Function: getCmdOption()
|
||||||
// Description: Handy little function to tell you if a command line flag and option was
|
// Description: Handy little function to tell you if a command line flag and option was
|
||||||
|
|
|
@ -96,8 +96,6 @@ int getNthBit(unsigned char byte, int ordinal); /// determines the bit placement
|
||||||
|
|
||||||
bool isInEnvironment(const char* environment);
|
bool isInEnvironment(const char* environment);
|
||||||
|
|
||||||
void loadRandomIdentifier(unsigned char* identifierBuffer, int numBytes);
|
|
||||||
|
|
||||||
const char* getCmdOption(int argc, const char * argv[],const char* option);
|
const char* getCmdOption(int argc, const char * argv[],const char* option);
|
||||||
bool cmdOptionExists(int argc, const char * argv[],const char* option);
|
bool cmdOptionExists(int argc, const char * argv[],const char* option);
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,6 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy
|
||||||
connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit()));
|
connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit()));
|
||||||
domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000);
|
domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000);
|
||||||
|
|
||||||
QTimer* pingNodesTimer = new QTimer(this);
|
|
||||||
connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes()));
|
|
||||||
pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000);
|
|
||||||
|
|
||||||
QTimer* silentNodeRemovalTimer = new QTimer(this);
|
QTimer* silentNodeRemovalTimer = new QTimer(this);
|
||||||
connect(silentNodeRemovalTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
connect(silentNodeRemovalTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
||||||
silentNodeRemovalTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
|
silentNodeRemovalTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
|
||||||
|
@ -84,7 +80,6 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
||||||
if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
||||||
setFinished(true);
|
setFinished(true);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Sending DS check in. There are" << NodeList::getInstance()->getNumNoReplyDomainCheckIns() << "unreplied.";
|
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue