From 15ba5f7ab1cc15204b8a17f5aa48c49f9e7acf32 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 13:48:31 -0800 Subject: [PATCH 01/46] correct OctreeServer config parsing --- libraries/octree-server/src/OctreeServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp index 73522565f9..6e58a0a987 100644 --- a/libraries/octree-server/src/OctreeServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -433,7 +433,7 @@ void OctreeServer::setArguments(int argc, char** argv) { void OctreeServer::parsePayload() { if (getPayload().size() > 0) { - QString config((const char*) _payload); + QString config(_payload); // Now, parse the config QStringList configList = config.split(" "); From 7d278300647a66805e510dfb20c1498fdf72a6ba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 14:23:39 -0800 Subject: [PATCH 02/46] domain-server patches while looking for payload/pool errors --- domain-server/src/DomainServer.cpp | 8 ++++---- libraries/shared/src/Assignment.cpp | 8 +------- libraries/shared/src/Assignment.h | 3 +-- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 6e4a4cdff4..b4ec326d37 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -575,7 +575,7 @@ void DomainServer::prepopulateStaticAssignmentFile() { Assignment voxelServerAssignment(Assignment::CreateCommand, Assignment::VoxelServerType, - (assignmentPool.isEmpty() ? NULL : assignmentPool.toLocal8Bit().constData())); + assignmentPool); voxelServerAssignment.setPayload(config.toUtf8()); @@ -615,8 +615,8 @@ void DomainServer::prepopulateStaticAssignmentFile() { } Assignment particleServerAssignment(Assignment::CreateCommand, - Assignment::ParticleServerType, - (assignmentPool.isEmpty() ? NULL : assignmentPool.toLocal8Bit().constData())); + Assignment::ParticleServerType, + assignmentPool); particleServerAssignment.setPayload(config.toLocal8Bit()); @@ -689,7 +689,7 @@ Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssi bool assignmentTypesMatch = (*assignment)->getType() == requestAssignment.getType(); bool nietherHasPool = (*assignment)->getPool().isEmpty() && requestAssignment.getPool().isEmpty(); bool assignmentPoolsMatch = (*assignment)->getPool() == requestAssignment.getPool(); - + if ((requestIsAllTypes || assignmentTypesMatch) && (nietherHasPool || assignmentPoolsMatch)) { Assignment* deployableAssignment = *assignment; diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index 2bff4ddcd0..76ee4b04cf 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -14,9 +14,6 @@ #include "Assignment.h" -const char IPv4_ADDRESS_DESIGNATOR = 4; -const char IPv6_ADDRESS_DESIGNATOR = 6; - Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) { switch (nodeType) { case NodeType::AudioMixer: @@ -95,10 +92,7 @@ Assignment::Assignment(const QByteArray& packet) : } packetStream >> _pool; - - if (!packetStream.atEnd()) { - _payload = packet.mid(packetStream.device()->pos()); - } + packetStream >> _payload; } #ifdef WIN32 diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index 418ea7fe09..fb69271db3 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -20,7 +20,6 @@ #include "NodeList.h" const int MAX_PAYLOAD_BYTES = 1024; -const int MAX_ASSIGNMENT_POOL_BYTES = 64 + sizeof('\0'); const QString emptyPool = QString(); @@ -76,7 +75,7 @@ public: Assignment::Location getLocation() const { return _location; } const QByteArray& getPayload() const { return _payload; } - void setPayload(const QByteArray& payload) { _payload = payload; } + void setPayload(const QByteArray& payload) { _payload = payload.left(MAX_PAYLOAD_BYTES); } void setPool(const QString& pool) { _pool = pool; }; const QString& getPool() const { return _pool; } From dbecb96a58b65895249fcfbbdd9d196722a315e7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 15:08:50 -0800 Subject: [PATCH 03/46] remove assignmentQueueMutex now that DS concurrency is gone --- domain-server/src/DomainServer.cpp | 27 ++++----------------------- domain-server/src/DomainServer.h | 1 - 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b4ec326d37..a124af4b40 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -38,7 +38,6 @@ const quint16 DOMAIN_SERVER_HTTP_PORT = 8080; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), - _assignmentQueueMutex(), _assignmentQueue(), _staticAssignmentFile(QString("%1/config.ds").arg(QCoreApplication::applicationDirPath())), _staticAssignmentFileData(NULL), @@ -467,9 +466,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // add the script assigment to the assignment queue // lock the assignment queue mutex since we're operating on a different thread than DS main - _assignmentQueueMutex.lock(); _assignmentQueue.push_back(scriptAssignment); - _assignmentQueueMutex.unlock(); } } else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) { if (path.startsWith(URI_NODE)) { @@ -514,9 +511,7 @@ void DomainServer::addReleasedAssignmentBackToQueue(Assignment* releasedAssignme _staticAssignments[i].resetUUID(); // put this assignment back in the queue so it goes out - _assignmentQueueMutex.lock(); _assignmentQueue.push_back(&_staticAssignments[i]); - _assignmentQueueMutex.unlock(); } else if (_staticAssignments[i].getUUID().isNull()) { // we are at the blank part of the static assignments - break out @@ -646,22 +641,18 @@ Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkI // pull the UUID passed with the check in if (_hasCompletedRestartHold) { - _assignmentQueueMutex.lock(); - // iterate the assignment queue to check for a match std::deque::iterator assignment = _assignmentQueue.begin(); while (assignment != _assignmentQueue.end()) { if ((*assignment)->getUUID() == checkInUUID) { // return the matched assignment - _assignmentQueueMutex.unlock(); return *assignment; } else { // no match, push deque iterator forwards assignment++; } } - - _assignmentQueueMutex.unlock(); + } else { for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { if (_staticAssignments[i].getUUID() == checkInUUID) { @@ -678,8 +669,6 @@ Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkI } Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssignment) { - _assignmentQueueMutex.lock(); - // this is an unassigned client talking to us directly for an assignment // go through our queue and see if there are any assignments to give out std::deque::iterator assignment = _assignmentQueue.begin(); @@ -713,22 +702,18 @@ Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssi } // stop looping, we've handed out an assignment - _assignmentQueueMutex.unlock(); return deployableAssignment; } else { // push forward the iterator to check the next assignment assignment++; } } - - _assignmentQueueMutex.unlock(); + return NULL; } void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) { - _assignmentQueueMutex.lock(); - std::deque::iterator assignment = _assignmentQueue.begin(); while (assignment != _assignmentQueue.end()) { @@ -740,8 +725,6 @@ void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) { assignment++; } } - - _assignmentQueueMutex.unlock(); } bool DomainServer::checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, @@ -796,10 +779,8 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { _staticAssignments[i].resetUUID(); qDebug() << "Adding static assignment to queue -" << _staticAssignments[i]; - - _assignmentQueueMutex.lock(); - _assignmentQueue.push_back(&_staticAssignments[i]); - _assignmentQueueMutex.unlock(); + + _assignmentQueue.push_back(&_staticAssignments[i]);gs } } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 26cdc765ba..ca83436c35 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -49,7 +49,6 @@ private: HTTPManager _HTTPManager; - QMutex _assignmentQueueMutex; std::deque _assignmentQueue; QFile _staticAssignmentFile; From d6431a3e7a5596fedf88e7be4bccd7212107d561 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 15:09:46 -0800 Subject: [PATCH 04/46] remove an extra gs --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index a124af4b40..603041be54 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -780,7 +780,7 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { qDebug() << "Adding static assignment to queue -" << _staticAssignments[i]; - _assignmentQueue.push_back(&_staticAssignments[i]);gs + _assignmentQueue.push_back(&_staticAssignments[i]); } } } From fe192ca2dece38dc8435f8c4feba79142a674d30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 14:23:39 -0800 Subject: [PATCH 05/46] domain-server patches while looking for payload/pool errors From 740d11027ccfb5605258731ff0adb9c128099b14 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 17:20:32 -0800 Subject: [PATCH 06/46] add QDataStream >> operator to Assignment --- libraries/shared/src/Assignment.cpp | 32 ++++++++++++----------------- libraries/shared/src/Assignment.h | 1 + 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index 76ee4b04cf..f8dcf3edca 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -52,6 +52,7 @@ Assignment::Assignment() : } Assignment::Assignment(Assignment::Command command, Assignment::Type type, const QString& pool, Assignment::Location location) : + _uuid(), _command(command), _type(type), _pool(pool), @@ -82,17 +83,7 @@ Assignment::Assignment(const QByteArray& packet) : QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); - uchar assignmentType; - packetStream >> assignmentType; - _type = (Assignment::Type) assignmentType; - - if (_command != Assignment::RequestCommand) { - // read the GUID for this assignment - packetStream >> _uuid; - } - - packetStream >> _pool; - packetStream >> _payload; + packetStream >> *this; } #ifdef WIN32 @@ -157,14 +148,17 @@ QDebug operator<<(QDebug debug, const Assignment &assignment) { } QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { - out << (quint8) assignment._type; - - // pack the UUID for this assignment, if this is an assignment create or deploy - if (assignment._command != Assignment::RequestCommand) { - out << assignment._uuid; - } - - out << assignment._pool << assignment._payload; + out << (quint8) assignment._type << assignment._uuid << assignment._pool << assignment._payload; return out; } + +QDataStream& operator>>(QDataStream &in, Assignment& assignment) { + quint8 packedType; + in >> packedType; + assignment._type = (Assignment::Type) packedType; + + in >> assignment._uuid >> assignment._pool >> assignment._payload; + + return in; +} diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index fb69271db3..dd34751b57 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -91,6 +91,7 @@ public: friend QDebug operator<<(QDebug debug, const Assignment& assignment); friend QDataStream& operator<<(QDataStream &out, const Assignment& assignment); + friend QDataStream& operator>>(QDataStream &in, Assignment& assignment); protected: QUuid _uuid; /// the 16 byte UUID for this assignment From 08b06cc59c048fa8553bab91067dce77cc049bc4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 Jan 2014 17:52:17 -0800 Subject: [PATCH 07/46] support for global collision callbacks in JS --- examples/gameoflife.js | 133 ++++++++++++++++++ examples/globalCollisionsExample.js | 26 ++++ examples/gun.js | 8 +- examples/paintGun.js | 6 +- interface/src/Application.cpp | 11 ++ libraries/particles/src/Particle.cpp | 120 +++++----------- libraries/particles/src/Particle.h | 27 ++-- .../particles/src/ParticleCollisionSystem.cpp | 15 ++ .../particles/src/ParticleCollisionSystem.h | 10 +- .../src/ParticlesScriptingInterface.h | 12 ++ libraries/script-engine/src/ScriptEngine.cpp | 7 +- libraries/script-engine/src/ScriptEngine.h | 4 +- libraries/shared/src/RegisteredMetaTypes.h | 1 + libraries/shared/src/SharedUtil.cpp | 100 ------------- libraries/shared/src/SharedUtil.h | 18 --- libraries/voxels/src/VoxelDetail.cpp | 37 +++++ libraries/voxels/src/VoxelDetail.h | 36 +++++ .../voxels/src/VoxelEditPacketSender.cpp | 100 +++++++++++++ libraries/voxels/src/VoxelEditPacketSender.h | 1 + libraries/voxels/src/VoxelTreeElement.h | 1 - .../voxels/src/VoxelsScriptingInterface.h | 16 --- 21 files changed, 448 insertions(+), 241 deletions(-) create mode 100644 examples/gameoflife.js create mode 100644 examples/globalCollisionsExample.js create mode 100644 libraries/voxels/src/VoxelDetail.cpp create mode 100644 libraries/voxels/src/VoxelDetail.h diff --git a/examples/gameoflife.js b/examples/gameoflife.js new file mode 100644 index 0000000000..09fae07204 --- /dev/null +++ b/examples/gameoflife.js @@ -0,0 +1,133 @@ +// Add your JavaScript for assignment below this line + +// The following is an example of Conway's Game of Life (http://en.wikipedia.org/wiki/Conway's_Game_of_Life) + +var NUMBER_OF_CELLS_EACH_DIMENSION = 64; +var NUMBER_OF_CELLS = NUMBER_OF_CELLS_EACH_DIMENSION * NUMBER_OF_CELLS_EACH_DIMENSION; + +var currentCells = []; +var nextCells = []; + +var METER_LENGTH = 1; +var cellScale = (NUMBER_OF_CELLS_EACH_DIMENSION * METER_LENGTH) / NUMBER_OF_CELLS_EACH_DIMENSION; + +// randomly populate the cell start values +for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) { + // create the array to hold this row + currentCells[i] = []; + + // create the array to hold this row in the nextCells array + nextCells[i] = []; + + for (var j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) { + currentCells[i][j] = Math.floor(Math.random() * 2); + + // put the same value in the nextCells array for first board draw + nextCells[i][j] = currentCells[i][j]; + } +} + +function isNeighbourAlive(i, j) { + if (i < 0 || i >= NUMBER_OF_CELLS_EACH_DIMENSION + || i < 0 || j >= NUMBER_OF_CELLS_EACH_DIMENSION) { + return 0; + } else { + return currentCells[i][j]; + } +} + +function updateCells() { + var i = 0; + var j = 0; + + for (i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) { + for (j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) { + // figure out the number of live neighbours for the i-j cell + var liveNeighbours = + isNeighbourAlive(i + 1, j - 1) + isNeighbourAlive(i + 1, j) + isNeighbourAlive(i + 1, j + 1) + + isNeighbourAlive(i, j - 1) + isNeighbourAlive(i, j + 1) + + isNeighbourAlive(i - 1, j - 1) + isNeighbourAlive(i - 1, j) + isNeighbourAlive(i - 1, j + 1); + + if (currentCells[i][j]) { + // live cell + + if (liveNeighbours < 2) { + // rule #1 - under-population - this cell will die + // mark it zero to mark the change + nextCells[i][j] = 0; + } else if (liveNeighbours < 4) { + // rule #2 - this cell lives + // mark it -1 to mark no change + nextCells[i][j] = -1; + } else { + // rule #3 - overcrowding - this cell dies + // mark it zero to mark the change + nextCells[i][j] = 0; + } + } else { + // dead cell + if (liveNeighbours == 3) { + // rule #4 - reproduction - this cell revives + // mark it one to mark the change + nextCells[i][j] = 1; + } else { + // this cell stays dead + // mark it -1 for no change + nextCells[i][j] = -1; + } + } + + if (Math.random() < 0.001) { + // Random mutation to keep things interesting in there. + nextCells[i][j] = 1; + } + } + } + + for (i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) { + for (j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) { + if (nextCells[i][j] != -1) { + // there has been a change to this cell, change the value in the currentCells array + currentCells[i][j] = nextCells[i][j]; + } + } + } +} + +function sendNextCells() { + for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) { + for (var j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) { + if (nextCells[i][j] != -1) { + // there has been a change to the state of this cell, send it + + // find the x and y position for this voxel, z = 0 + var x = j * cellScale; + var y = i * cellScale; + + // queue a packet to add a voxel for the new cell + var color = (nextCells[i][j] == 1) ? 255 : 1; + Voxels.setVoxel(x, y, 0, cellScale, color, color, color); + } + } + } +} + +var sentFirstBoard = false; + +function step() { +print("step()..."); + if (sentFirstBoard) { + // we've already sent the first full board, perform a step in time + updateCells(); + } else { + // this will be our first board send + sentFirstBoard = true; + } + + sendNextCells(); +} + +print("here"); +Agent.willSendVisualDataCallback.connect(step); +Voxels.setPacketsPerSecond(200); +print("now here"); diff --git a/examples/globalCollisionsExample.js b/examples/globalCollisionsExample.js new file mode 100644 index 0000000000..4db4c808e5 --- /dev/null +++ b/examples/globalCollisionsExample.js @@ -0,0 +1,26 @@ +// +// globalCollisionsExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 1/29/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Controller class +// +// + + +function particleCollisionWithVoxel(particle, voxel) { + print("particleCollisionWithVoxel().."); + print(" particle.getID()=" + particle.id); + print(" voxel color...=" + voxel.red + ", " + voxel.green + ", " + voxel.blue); +} + +function particleCollisionWithParticle(particleA, particleB) { + print("particleCollisionWithParticle().."); + print(" particleA.getID()=" + particleA.id); + print(" particleB.getID()=" + particleB.id); +} + +Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel); +Particles.particleCollisionWithParticle.connect(particleCollisionWithParticle); diff --git a/examples/gun.js b/examples/gun.js index 30d2b41449..3f8eefe3e2 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -72,13 +72,13 @@ function checkController() { " function collisionWithVoxel(voxel) { " + " print('collisionWithVoxel(voxel)... '); " + " print('myID=' + Particle.getID() + '\\n'); " + - " var voxelColor = voxel.getColor();" + - " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " + + " var voxelColor = { red: voxel.red, green: voxel.green, blue: voxel.blue };" + + " var voxelAt = { x: voxel.x, y: voxel.y, z: voxel.z };" + + " var voxelScale = voxel.s;" + + " print('voxelColor=' + voxel.red + ', ' + voxel.green + ', ' + voxel.blue + '\\n'); " + " var myColor = Particle.getColor();" + " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " + " Particle.setColor(voxelColor); " + - " var voxelAt = voxel.getPosition();" + - " var voxelScale = voxel.getScale();" + " Voxels.eraseVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " + " print('Voxels.eraseVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + " } " + diff --git a/examples/paintGun.js b/examples/paintGun.js index 0cbe3ff366..b78e6abb0b 100644 --- a/examples/paintGun.js +++ b/examples/paintGun.js @@ -65,13 +65,13 @@ function checkController() { " function collisionWithVoxel(voxel) { " + " print('collisionWithVoxel(voxel)... '); " + " print('myID=' + Particle.getID() + '\\n'); " + - " var voxelColor = voxel.getColor();" + + " var voxelColor = { red: voxel.red, green: voxel.green, blue: voxel.blue };" + + " var voxelAt = { x: voxel.x, y: voxel.y, z: voxel.z };" + + " var voxelScale = voxel.s;" + " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " + " var myColor = Particle.getColor();" + " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " + " Particle.setColor(voxelColor); " + - " var voxelAt = voxel.getPosition();" + - " var voxelScale = voxel.getScale();" + " Voxels.setVoxel(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale, 255, 255, 0); " + " print('Voxels.setVoxel(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + " } " + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6578618e5f..f300c79c67 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1879,6 +1879,17 @@ void Application::init() { _particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager); + // connect the _particleCollisionSystem to our script engine's ParticleScriptingInterface + connect(&_particleCollisionSystem, + SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&)), + ScriptEngine::getParticlesScriptingInterface(), + SLOT(forwardParticleCollisionWithVoxel(const ParticleID&, const VoxelDetail&))); + + connect(&_particleCollisionSystem, + SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&)), + ScriptEngine::getParticlesScriptingInterface(), + SLOT(forwardParticleCollisionWithParticle(const ParticleID&, const ParticleID&))); + _palette.init(_glWidget->width(), _glWidget->height()); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelAddMode), 0, 0); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelDeleteMode), 0, 1); diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 933bf36830..557d4ca87f 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -13,6 +13,8 @@ #include #include // usecTimestampNow() #include +#include + // This is not ideal, but adding script-engine as a linked library, will cause a circular reference // I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others @@ -831,7 +833,7 @@ void Particle::update(const uint64_t& now) { bool shouldDie = (getAge() > getLifetime()) || getShouldDie() || (!isInHand && isStopped && isReallyOld); setShouldDie(shouldDie); - runUpdateScript(); // allow the javascript to alter our state + executeUpdateScripts(); // allow the javascript to alter our state // If the ball is in hand, it doesn't move or have gravity effect it if (!isInHand) { @@ -853,106 +855,62 @@ void Particle::update(const uint64_t& now) { } } -void Particle::runUpdateScript() { +void Particle::startParticleScriptContext(ScriptEngine& engine, ParticleScriptObject& particleScriptable) { + if (_voxelEditSender) { + engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender); + } + if (_particleEditSender) { + engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender); + } + + // Add the "this" Particle object + engine.registerGlobalObject("Particle", &particleScriptable); + engine.evaluate(); +} + +void Particle::endParticleScriptContext(ScriptEngine& engine, ParticleScriptObject& particleScriptable) { + if (_voxelEditSender) { + _voxelEditSender->releaseQueuedMessages(); + } + if (_particleEditSender) { + _particleEditSender->releaseQueuedMessages(); + } +} + +void Particle::executeUpdateScripts() { + // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - ScriptEngine engine(_script); // no menu or controller interface... - - if (_voxelEditSender) { - engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender); - } - if (_particleEditSender) { - engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender); - } - - // Add the Particle object + ScriptEngine engine(_script); ParticleScriptObject particleScriptable(this); - engine.registerGlobalObject("Particle", &particleScriptable); - - // init and evaluate the script, but return so we can emit the collision - engine.evaluate(); - + startParticleScriptContext(engine, particleScriptable); particleScriptable.emitUpdate(); - - // it seems like we may need to send out particle edits if the state of our particle was changed. - - if (_voxelEditSender) { - _voxelEditSender->releaseQueuedMessages(); - } - if (_particleEditSender) { - _particleEditSender->releaseQueuedMessages(); - } + endParticleScriptContext(engine, particleScriptable); } } void Particle::collisionWithParticle(Particle* other) { + // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - ScriptEngine engine(_script); // no menu or controller interface... - - if (_voxelEditSender) { - engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender); - } - if (_particleEditSender) { - engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender); - } - - // Add the Particle object + ScriptEngine engine(_script); ParticleScriptObject particleScriptable(this); - engine.registerGlobalObject("Particle", &particleScriptable); - - // init and evaluate the script, but return so we can emit the collision - engine.evaluate(); - + startParticleScriptContext(engine, particleScriptable); ParticleScriptObject otherParticleScriptable(other); particleScriptable.emitCollisionWithParticle(&otherParticleScriptable); - - // it seems like we may need to send out particle edits if the state of our particle was changed. - - if (_voxelEditSender) { - _voxelEditSender->releaseQueuedMessages(); - } - if (_particleEditSender) { - _particleEditSender->releaseQueuedMessages(); - } + endParticleScriptContext(engine, particleScriptable); } } void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) { + // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - - ScriptEngine engine(_script); // no menu or controller interface... - - // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so - // we can use the same ones as our context. - if (_voxelEditSender) { - engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender); - } - if (_particleEditSender) { - engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender); - } - - // Add the Particle object + ScriptEngine engine(_script); ParticleScriptObject particleScriptable(this); - engine.registerGlobalObject("Particle", &particleScriptable); - - // init and evaluate the script, but return so we can emit the collision - engine.evaluate(); - - VoxelDetailScriptObject voxelDetailsScriptable(voxelDetails); - particleScriptable.emitCollisionWithVoxel(&voxelDetailsScriptable); - - // it seems like we may need to send out particle edits if the state of our particle was changed. - - if (_voxelEditSender) { - _voxelEditSender->releaseQueuedMessages(); - } - if (_particleEditSender) { - _particleEditSender->releaseQueuedMessages(); - } + startParticleScriptContext(engine, particleScriptable); + particleScriptable.emitCollisionWithVoxel(*voxelDetails); + endParticleScriptContext(engine, particleScriptable); } } - - void Particle::setAge(float age) { uint64_t ageInUsecs = age * USECS_PER_SECOND; _created = usecTimestampNow() - ageInUsecs; diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 456eb7ef4f..ec2e389cb5 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -20,13 +20,16 @@ #include #include -class VoxelsScriptingInterface; -class ParticlesScriptingInterface; -class VoxelEditPacketSender; +class Particle; class ParticleEditPacketSender; class ParticleProperties; -class Particle; +class ParticlesScriptingInterface; +class ParticleScriptObject; class ParticleTree; +class ScriptEngine; +class VoxelEditPacketSender; +class VoxelsScriptingInterface; +struct VoxelDetail; const uint32_t NEW_PARTICLE = 0xFFFFFFFF; const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF; @@ -227,7 +230,8 @@ public: const glm::vec3& getModelTranslation() const { return _modelTranslation; } const glm::quat& getModelRotation() const { return _modelRotation; } float getModelScale() const { return _modelScale; } - + + ParticleID getParticleID() const { return ParticleID(getID(), getCreatorTokenID(), getID() != UNKNOWN_PARTICLE_ID); } ParticleProperties getProperties() const; /// The last updated/simulated time of this particle from the time perspective of the authoritative server/source @@ -318,11 +322,9 @@ protected: static VoxelEditPacketSender* _voxelEditSender; static ParticleEditPacketSender* _particleEditSender; - void runUpdateScript(); - static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3); - static void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3); - static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color); - static void xColorFromScriptValue(const QScriptValue &object, xColor& color); + void startParticleScriptContext(ScriptEngine& engine, ParticleScriptObject& particleScriptable); + void endParticleScriptContext(ScriptEngine& engine, ParticleScriptObject& particleScriptable); + void executeUpdateScripts(); void setAge(float age); @@ -366,10 +368,11 @@ class ParticleScriptObject : public QObject { Q_OBJECT public: ParticleScriptObject(Particle* particle) { _particle = particle; } + //~ParticleScriptObject() { qDebug() << "~ParticleScriptObject() this=" << this; } void emitUpdate() { emit update(); } void emitCollisionWithParticle(QObject* other) { emit collisionWithParticle(other); } - void emitCollisionWithVoxel(QObject* voxel) { emit collisionWithVoxel(voxel); } + void emitCollisionWithVoxel(const VoxelDetail& voxel) { emit collisionWithVoxel(voxel); } public slots: unsigned int getID() const { return _particle->getID(); } @@ -414,7 +417,7 @@ public slots: signals: void update(); - void collisionWithVoxel(QObject* voxel); + void collisionWithVoxel(const VoxelDetail& voxel); void collisionWithParticle(QObject* other); private: diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index a2394935b1..143b1ddcbd 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -68,6 +68,17 @@ void ParticleCollisionSystem::checkParticle(Particle* particle) { updateCollisionWithAvatars(particle); } +void ParticleCollisionSystem::emitGlobalParicleCollisionWithVoxel(Particle* particle, VoxelDetail* voxelDetails) { + ParticleID particleID = particle->getParticleID(); + emit particleCollisionWithVoxel(particleID, *voxelDetails); +} + +void ParticleCollisionSystem::emitGlobalParicleCollisionWithParticle(Particle* particleA, Particle* particleB) { + ParticleID idA = particleA->getParticleID(); + ParticleID idB = particleB->getParticleID(); + emit particleCollisionWithParticle(idA, idB); +} + void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) { glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE); float radius = particle->getRadius() * (float)(TREE_SCALE); @@ -83,6 +94,9 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) { // let the particles run their collision scripts if they have them particle->collisionWithVoxel(voxelDetails); + // let the global script run their collision scripts for particles if they have them + emitGlobalParicleCollisionWithVoxel(particle, voxelDetails); + updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY); collisionInfo._penetration /= (float)(TREE_SCALE); particle->applyHardCollision(collisionInfo); @@ -110,6 +124,7 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) if (glm::dot(relativeVelocity, penetration) > 0.0f) { particleA->collisionWithParticle(particleB); particleB->collisionWithParticle(particleA); + emitGlobalParicleCollisionWithParticle(particleA, particleB); glm::vec3 axis = glm::normalize(penetration); glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis; diff --git a/libraries/particles/src/ParticleCollisionSystem.h b/libraries/particles/src/ParticleCollisionSystem.h index 4a61693fa6..9baf9bfd05 100644 --- a/libraries/particles/src/ParticleCollisionSystem.h +++ b/libraries/particles/src/ParticleCollisionSystem.h @@ -31,7 +31,8 @@ class VoxelTree; const glm::vec3 NO_ADDED_VELOCITY = glm::vec3(0); -class ParticleCollisionSystem { +class ParticleCollisionSystem : public QObject { +Q_OBJECT public: ParticleCollisionSystem(ParticleEditPacketSender* packetSender = NULL, ParticleTree* particles = NULL, VoxelTree* voxels = NULL, AbstractAudioInterface* audio = NULL, @@ -51,9 +52,14 @@ public: void queueParticlePropertiesUpdate(Particle* particle); void updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency); +signals: + void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel); + void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB); + private: static bool updateOperation(OctreeElement* element, void* extraData); - + void emitGlobalParicleCollisionWithVoxel(Particle* particle, VoxelDetail* voxelDetails); + void emitGlobalParicleCollisionWithParticle(Particle* particleA, Particle* particleB); ParticleEditPacketSender* _packetSender; ParticleTree* _particles; diff --git a/libraries/particles/src/ParticlesScriptingInterface.h b/libraries/particles/src/ParticlesScriptingInterface.h index 9a3ceb51af..2a6a5e24f0 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.h +++ b/libraries/particles/src/ParticlesScriptingInterface.h @@ -53,7 +53,19 @@ public slots: /// finds particles within the search sphere specified by the center point and radius /// this function will not find any particles in script engine contexts which don't have access to particles QVector findParticles(const glm::vec3& center, float radius) const; + + /// inbound slots for external collision systems + void forwardParticleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel) { + emit particleCollisionWithVoxel(particleID, voxel); + } + + void forwardParticleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB) { + emit particleCollisionWithParticle(idA, idB); + } +signals: + void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel); + void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB); private: void queueParticleMessage(PACKET_TYPE packetType, ParticleID particleID, const ParticleProperties& properties); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 28cb49f6f7..9db1254f80 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -114,10 +115,12 @@ void ScriptEngine::init() { _voxelsScriptingInterface.init(); _particlesScriptingInterface.init(); - // register meta-type for glm::vec3 conversions + // register various meta-types registerMetaTypes(&_engine); - + registerVoxelMetaTypes(&_engine); + //registerParticleMetaTypes(&_engine); registerEventTypes(&_engine); + qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); qScriptRegisterSequenceMetaType >(&_engine); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index ef55e14109..c2188cca63 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -41,10 +41,10 @@ public: ~ScriptEngine(); /// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener - VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; } + static VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; } /// Access the ParticlesScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener - ParticlesScriptingInterface* getParticlesScriptingInterface() { return &_particlesScriptingInterface; } + static ParticlesScriptingInterface* getParticlesScriptingInterface() { return &_particlesScriptingInterface; } /// Access the DataServerScriptingInterface for access to its underlying UUID const DataServerScriptingInterface& getDataServerScriptingInterface() { return _dataServerScriptingInterface; } diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index de667c9ed8..b198add7c2 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -22,6 +22,7 @@ Q_DECLARE_METATYPE(glm::vec2) Q_DECLARE_METATYPE(glm::quat) Q_DECLARE_METATYPE(xColor) + void registerMetaTypes(QScriptEngine* engine); QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3); diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 54a4291c25..e2c5b912c0 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -231,106 +231,6 @@ void sharedMessageHandler(QtMsgType type, const QMessageLogContext& context, con fprintf(stdout, "%s", message.toLocal8Bit().constData()); } -////////////////////////////////////////////////////////////////////////////////////////// -// Function: createVoxelEditMessage() -// Description: creates an "insert" or "remove" voxel message for a voxel code -// corresponding to the closest voxel which encloses a cube with -// lower corners at x,y,z, having side of length S. -// The input values x,y,z range 0.0 <= v < 1.0 -// message should be either 'S' for SET or 'E' for ERASE -// -// IMPORTANT: The buffer is returned to you a buffer which you MUST delete when you are -// done with it. -// -// HACK ATTACK: Well, what if this is larger than the MTU? That's the caller's problem, we -// just truncate the message -// -// Complaints: Brad :) -#define GUESS_OF_VOXELCODE_SIZE 10 -#define MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE 1500 -#define SIZE_OF_COLOR_DATA sizeof(rgbColor) -bool createVoxelEditMessage(unsigned char command, short int sequence, - int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) { - - bool success = true; // assume the best - int messageSize = MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE; // just a guess for now - unsigned char* messageBuffer = new unsigned char[messageSize]; - - int numBytesPacketHeader = populateTypeAndVersion(messageBuffer, command); - unsigned short int* sequenceAt = (unsigned short int*) &messageBuffer[numBytesPacketHeader]; - *sequenceAt = sequence; - - // pack in timestamp - uint64_t now = usecTimestampNow(); - uint64_t* timeAt = (uint64_t*)&messageBuffer[numBytesPacketHeader + sizeof(sequence)]; - *timeAt = now; - - unsigned char* copyAt = &messageBuffer[numBytesPacketHeader + sizeof(sequence) + sizeof(now)]; - int actualMessageSize = numBytesPacketHeader + sizeof(sequence) + sizeof(now); - - for (int i = 0; i < voxelCount && success; i++) { - // get the coded voxel - unsigned char* voxelData = pointToVoxel(voxelDetails[i].x,voxelDetails[i].y,voxelDetails[i].z, - voxelDetails[i].s,voxelDetails[i].red,voxelDetails[i].green,voxelDetails[i].blue); - - int lengthOfVoxelData = bytesRequiredForCodeLength(*voxelData)+SIZE_OF_COLOR_DATA; - - // make sure we have room to copy this voxel - if (actualMessageSize + lengthOfVoxelData > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { - success = false; - } else { - // add it to our message - memcpy(copyAt, voxelData, lengthOfVoxelData); - copyAt += lengthOfVoxelData; - actualMessageSize += lengthOfVoxelData; - } - // cleanup - delete[] voxelData; - } - - if (success) { - // finally, copy the result to the output - bufferOut = new unsigned char[actualMessageSize]; - sizeOut = actualMessageSize; - memcpy(bufferOut, messageBuffer, actualMessageSize); - } - - delete[] messageBuffer; // clean up our temporary buffer - return success; -} - -/// encodes the voxel details portion of a voxel edit message -bool encodeVoxelEditMessageDetails(unsigned char command, int voxelCount, VoxelDetail* voxelDetails, - unsigned char* bufferOut, int sizeIn, int& sizeOut) { - - bool success = true; // assume the best - unsigned char* copyAt = bufferOut; - sizeOut = 0; - - for (int i = 0; i < voxelCount && success; i++) { - // get the coded voxel - unsigned char* voxelData = pointToVoxel(voxelDetails[i].x,voxelDetails[i].y,voxelDetails[i].z, - voxelDetails[i].s,voxelDetails[i].red,voxelDetails[i].green,voxelDetails[i].blue); - - int lengthOfVoxelData = bytesRequiredForCodeLength(*voxelData)+SIZE_OF_COLOR_DATA; - - // make sure we have room to copy this voxel - if (sizeOut + lengthOfVoxelData > sizeIn) { - success = false; - } else { - // add it to our message - memcpy(copyAt, voxelData, lengthOfVoxelData); - copyAt += lengthOfVoxelData; - sizeOut += lengthOfVoxelData; - } - // cleanup - delete[] voxelData; - } - - return success; -} - - unsigned char* pointToOctalCode(float x, float y, float z, float s) { return pointToVoxel(x, y, z, s); } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 399bf40204..c25d2c5f0d 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -94,27 +94,9 @@ bool cmdOptionExists(int argc, const char * argv[],const char* option); void sharedMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); -struct VoxelDetail { - float x; - float y; - float z; - float s; - unsigned char red; - unsigned char green; - unsigned char blue; -}; - unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r = 0, unsigned char g = 0, unsigned char b = 0); unsigned char* pointToOctalCode(float x, float y, float z, float s); -// Creates a full Voxel edit message, including command header, sequence, and details -bool createVoxelEditMessage(unsigned char command, short int sequence, - int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut); - -/// encodes the voxel details portion of a voxel edit message -bool encodeVoxelEditMessageDetails(unsigned char command, int voxelCount, VoxelDetail* voxelDetails, - unsigned char* bufferOut, int sizeIn, int& sizeOut); - #ifdef _WIN32 void usleep(int waitTime); #endif diff --git a/libraries/voxels/src/VoxelDetail.cpp b/libraries/voxels/src/VoxelDetail.cpp new file mode 100644 index 0000000000..d4ab5cafcb --- /dev/null +++ b/libraries/voxels/src/VoxelDetail.cpp @@ -0,0 +1,37 @@ +// +// VoxelDetail.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 1/29/2014 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +#include "VoxelDetail.h" + +void registerVoxelMetaTypes(QScriptEngine* engine) { + qScriptRegisterMetaType(engine, voxelDetailToScriptValue, voxelDetailFromScriptValue); +} + +QScriptValue voxelDetailToScriptValue(QScriptEngine* engine, const VoxelDetail& voxelDetail) { + QScriptValue obj = engine->newObject(); + obj.setProperty("x", voxelDetail.x * (float)TREE_SCALE); + obj.setProperty("y", voxelDetail.y * (float)TREE_SCALE); + obj.setProperty("z", voxelDetail.z * (float)TREE_SCALE); + obj.setProperty("s", voxelDetail.s * (float)TREE_SCALE); + obj.setProperty("red", voxelDetail.red); + obj.setProperty("green", voxelDetail.green); + obj.setProperty("blue", voxelDetail.blue); + return obj; +} + +void voxelDetailFromScriptValue(const QScriptValue &object, VoxelDetail& voxelDetail) { + voxelDetail.x = object.property("x").toVariant().toFloat() / (float)TREE_SCALE; + voxelDetail.y = object.property("y").toVariant().toFloat() / (float)TREE_SCALE; + voxelDetail.z = object.property("z").toVariant().toFloat() / (float)TREE_SCALE; + voxelDetail.s = object.property("s").toVariant().toFloat() / (float)TREE_SCALE; + voxelDetail.red = object.property("red").toVariant().toInt(); + voxelDetail.green = object.property("green").toVariant().toInt(); + voxelDetail.blue = object.property("blue").toVariant().toInt(); +} + + + diff --git a/libraries/voxels/src/VoxelDetail.h b/libraries/voxels/src/VoxelDetail.h new file mode 100644 index 0000000000..ca1ff3940b --- /dev/null +++ b/libraries/voxels/src/VoxelDetail.h @@ -0,0 +1,36 @@ +// +// VoxelDetail.h +// hifi +// +// Created by Brad Hefta-Gaub on 1/29/2014 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// + +#ifndef __hifi__VoxelDetail__ +#define __hifi__VoxelDetail__ + +#include + +#include +#include "VoxelConstants.h" + +struct VoxelDetail { + float x; + float y; + float z; + float s; + unsigned char red; + unsigned char green; + unsigned char blue; +}; + +Q_DECLARE_METATYPE(VoxelDetail) + +void registerVoxelMetaTypes(QScriptEngine* engine); + +QScriptValue voxelDetailToScriptValue(QScriptEngine* engine, const VoxelDetail& color); +void voxelDetailFromScriptValue(const QScriptValue &object, VoxelDetail& color); + + +#endif /* defined(__hifi__VoxelDetail__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index af3ae63377..e776a8f665 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -14,6 +14,106 @@ #include #include "VoxelEditPacketSender.h" +////////////////////////////////////////////////////////////////////////////////////////// +// Function: createVoxelEditMessage() +// Description: creates an "insert" or "remove" voxel message for a voxel code +// corresponding to the closest voxel which encloses a cube with +// lower corners at x,y,z, having side of length S. +// The input values x,y,z range 0.0 <= v < 1.0 +// message should be either 'S' for SET or 'E' for ERASE +// +// IMPORTANT: The buffer is returned to you a buffer which you MUST delete when you are +// done with it. +// +// HACK ATTACK: Well, what if this is larger than the MTU? That's the caller's problem, we +// just truncate the message +// +// Complaints: Brad :) +#define GUESS_OF_VOXELCODE_SIZE 10 +#define MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE 1500 +#define SIZE_OF_COLOR_DATA sizeof(rgbColor) +bool createVoxelEditMessage(unsigned char command, short int sequence, + int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) { + + bool success = true; // assume the best + int messageSize = MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE; // just a guess for now + unsigned char* messageBuffer = new unsigned char[messageSize]; + + int numBytesPacketHeader = populateTypeAndVersion(messageBuffer, command); + unsigned short int* sequenceAt = (unsigned short int*) &messageBuffer[numBytesPacketHeader]; + *sequenceAt = sequence; + + // pack in timestamp + uint64_t now = usecTimestampNow(); + uint64_t* timeAt = (uint64_t*)&messageBuffer[numBytesPacketHeader + sizeof(sequence)]; + *timeAt = now; + + unsigned char* copyAt = &messageBuffer[numBytesPacketHeader + sizeof(sequence) + sizeof(now)]; + int actualMessageSize = numBytesPacketHeader + sizeof(sequence) + sizeof(now); + + for (int i = 0; i < voxelCount && success; i++) { + // get the coded voxel + unsigned char* voxelData = pointToVoxel(voxelDetails[i].x,voxelDetails[i].y,voxelDetails[i].z, + voxelDetails[i].s,voxelDetails[i].red,voxelDetails[i].green,voxelDetails[i].blue); + + int lengthOfVoxelData = bytesRequiredForCodeLength(*voxelData)+SIZE_OF_COLOR_DATA; + + // make sure we have room to copy this voxel + if (actualMessageSize + lengthOfVoxelData > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { + success = false; + } else { + // add it to our message + memcpy(copyAt, voxelData, lengthOfVoxelData); + copyAt += lengthOfVoxelData; + actualMessageSize += lengthOfVoxelData; + } + // cleanup + delete[] voxelData; + } + + if (success) { + // finally, copy the result to the output + bufferOut = new unsigned char[actualMessageSize]; + sizeOut = actualMessageSize; + memcpy(bufferOut, messageBuffer, actualMessageSize); + } + + delete[] messageBuffer; // clean up our temporary buffer + return success; +} + +/// encodes the voxel details portion of a voxel edit message +bool encodeVoxelEditMessageDetails(unsigned char command, int voxelCount, VoxelDetail* voxelDetails, + unsigned char* bufferOut, int sizeIn, int& sizeOut) { + + bool success = true; // assume the best + unsigned char* copyAt = bufferOut; + sizeOut = 0; + + for (int i = 0; i < voxelCount && success; i++) { + // get the coded voxel + unsigned char* voxelData = pointToVoxel(voxelDetails[i].x,voxelDetails[i].y,voxelDetails[i].z, + voxelDetails[i].s,voxelDetails[i].red,voxelDetails[i].green,voxelDetails[i].blue); + + int lengthOfVoxelData = bytesRequiredForCodeLength(*voxelData)+SIZE_OF_COLOR_DATA; + + // make sure we have room to copy this voxel + if (sizeOut + lengthOfVoxelData > sizeIn) { + success = false; + } else { + // add it to our message + memcpy(copyAt, voxelData, lengthOfVoxelData); + copyAt += lengthOfVoxelData; + sizeOut += lengthOfVoxelData; + } + // cleanup + delete[] voxelData; + } + + return success; +} + + void VoxelEditPacketSender::sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail) { // allows app to disable sending if for example voxels have been disabled diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index ec9b74dff8..c09c3b533a 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -12,6 +12,7 @@ #define __shared__VoxelEditPacketSender__ #include +#include "VoxelDetail.h" /// Utility for processing, packing, queueing and sending of outbound edit voxel messages. class VoxelEditPacketSender : public OctreeEditPacketSender { diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h index 86732f4b66..028d2456eb 100644 --- a/libraries/voxels/src/VoxelTreeElement.h +++ b/libraries/voxels/src/VoxelTreeElement.h @@ -91,5 +91,4 @@ protected: nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes }; - #endif /* defined(__hifi__VoxelTreeElement__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index 97bdfb2c59..f5f5114154 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -57,20 +57,4 @@ private: void queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails); }; -class VoxelDetailScriptObject : public QObject { - Q_OBJECT -public: - VoxelDetailScriptObject(VoxelDetail* voxelDetail) { _voxelDetail = voxelDetail; } - -public slots: - /// position in meter units - glm::vec3 getPosition() const { return glm::vec3(_voxelDetail->x, _voxelDetail->y, _voxelDetail->z) * (float)TREE_SCALE; } - xColor getColor() const { xColor color = { _voxelDetail->red, _voxelDetail->green, _voxelDetail->blue }; return color; } - /// scale in meter units - float getScale() const { return _voxelDetail->s * (float)TREE_SCALE; } - -private: - VoxelDetail* _voxelDetail; -}; - #endif /* defined(__hifi__VoxelsScriptingInterface__) */ From a04879936735013c40b7ac983805541159b7d0f3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 Jan 2014 20:54:22 -0800 Subject: [PATCH 08/46] fix header comment --- examples/findParticleExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/findParticleExample.js b/examples/findParticleExample.js index f582ee6469..bd20e6ded7 100644 --- a/examples/findParticleExample.js +++ b/examples/findParticleExample.js @@ -1,5 +1,5 @@ // -// editParticleExample.js +// findParticleExample.js // hifi // // Created by Brad Hefta-Gaub on 1/24/14. From 01c369716eadc8ad55cb13b909dfedb621ecdd40 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 Jan 2014 20:55:12 -0800 Subject: [PATCH 09/46] implement a basic exampple of ride along with a particle --- examples/rideAlongWithAParticleExample.js | 50 +++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 examples/rideAlongWithAParticleExample.js diff --git a/examples/rideAlongWithAParticleExample.js b/examples/rideAlongWithAParticleExample.js new file mode 100644 index 0000000000..eca9fe7f4c --- /dev/null +++ b/examples/rideAlongWithAParticleExample.js @@ -0,0 +1,50 @@ +// +// rideAlongWithAParticleExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 1/24/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates "finding" particles +// + +var iteration = 0; +var lengthOfRide = 2000; // in iterations + +var particleA = Particles.addParticle( + { + position: { x: 10, y: 0, z: 10 }, + velocity: { x: 5, y: 0, z: 5 }, + gravity: { x: 0, y: 0, z: 0 }, + radius : 0.1, + color: { red: 0, green: 255, blue: 0 }, + damping: 0, + lifetime: (lengthOfRide * 60) + 1 + }); + +function rideWithParticle() { + + if (iteration <= lengthOfRide) { + + // Check to see if we've been notified of the actual identity of the particles we created + if (!particleA.isKnownID) { + particleA = Particles.identifyParticle(particleA); + } + + var propertiesA = Particles.getParticleProperties(particleA); + var newPosition = propertiesA.position; + MyAvatar.position = { x: propertiesA.position.x, + y: propertiesA.position.y + 2, + z: propertiesA.position.z }; + } else { + Agent.stop(); + } + + iteration++; + print("iteration="+iteration); +} + + +// register the call back so it fires before each data send +Agent.willSendVisualDataCallback.connect(rideWithParticle); + From da5e0f55b6d8bf4ed9b53860599f03928f8cebd5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 30 Jan 2014 12:26:50 -0800 Subject: [PATCH 10/46] add easier support for key codes in JS by adding text property and auto-detecting isShifted --- examples/controllerExample.js | 101 +++++++++++++- libraries/script-engine/src/EventTypes.cpp | 155 ++++++++++++++++++++- libraries/script-engine/src/EventTypes.h | 11 +- 3 files changed, 260 insertions(+), 7 deletions(-) diff --git a/examples/controllerExample.js b/examples/controllerExample.js index c1b33b24a5..95561dc9dc 100644 --- a/examples/controllerExample.js +++ b/examples/controllerExample.js @@ -48,6 +48,15 @@ function checkController() { function keyPressEvent(event) { print("keyPressEvent event.key=" + event.key); + print("keyPressEvent event.text=" + event.text); + + print("keyPressEvent event.isShifted=" + event.isShifted); + print("keyPressEvent event.isControl=" + event.isControl); + print("keyPressEvent event.isMeta=" + event.isMeta); + print("keyPressEvent event.isAlt=" + event.isAlt); + print("keyPressEvent event.isKeypad=" + event.isKeypad); + + if (event.key == "A".charCodeAt(0)) { print("the A key was pressed"); } @@ -77,14 +86,102 @@ Agent.willSendVisualDataCallback.connect(checkController); // Map keyPress and mouse move events to our callbacks Controller.keyPressEvent.connect(keyPressEvent); -var AKeyEvent = { +var KeyEvent_A = { key: "A".charCodeAt(0), + text: "A", isShifted: false, isMeta: false }; +var KeyEvent_a = { + text: "a", + isShifted: false, + isMeta: false +}; + +var KeyEvent_a2 = { + key: "a".charCodeAt(0), + isShifted: false, + isMeta: false +}; + +var KeyEvent_a3 = { + text: "a" +}; + +var KeyEvent_A2 = { + text: "A" +}; + + +var KeyEvent_9 = { + text: "9" +}; + +var KeyEvent_Num = { + text: "#" +}; + +var KeyEvent_At = { + text: "@" +}; + +var KeyEvent_MetaAt = { + text: "@", + isMeta: true +}; + +var KeyEvent_Up = { + text: "up" +}; +var KeyEvent_Down = { + text: "down" +}; +var KeyEvent_Left = { + text: "left" +}; +var KeyEvent_Right = { + text: "right" +}; + // prevent the A key from going through to the application -Controller.captureKeyEvents(AKeyEvent); +print("KeyEvent_A"); +Controller.captureKeyEvents(KeyEvent_A); + +print("KeyEvent_A2"); +Controller.captureKeyEvents(KeyEvent_A2); + +print("KeyEvent_a"); +Controller.captureKeyEvents(KeyEvent_a); + +print("KeyEvent_a2"); +Controller.captureKeyEvents(KeyEvent_a2); + +print("KeyEvent_a3"); +Controller.captureKeyEvents(KeyEvent_a3); + +print("KeyEvent_9"); +Controller.captureKeyEvents(KeyEvent_9); + +print("KeyEvent_Num"); +Controller.captureKeyEvents(KeyEvent_Num); + +print("KeyEvent_At"); +Controller.captureKeyEvents(KeyEvent_At); + +print("KeyEvent_MetaAt"); +Controller.captureKeyEvents(KeyEvent_MetaAt); + +print("KeyEvent_Up"); +Controller.captureKeyEvents(KeyEvent_Up); +print("KeyEvent_Down"); +Controller.captureKeyEvents(KeyEvent_Down); +print("KeyEvent_Left"); +Controller.captureKeyEvents(KeyEvent_Left); +print("KeyEvent_Right"); +Controller.captureKeyEvents(KeyEvent_Right); + + Controller.mouseMoveEvent.connect(mouseMoveEvent); diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index 5c4ab7f2a7..ff27282b73 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -8,22 +8,72 @@ // Used to register meta-types with Qt for very various event types so that they can be exposed to our // scripting engine +#include #include "EventTypes.h" KeyEvent::KeyEvent() { key = 0; + text = QString(""); isShifted = false; isMeta = false; + isControl = false; isValid = false; } KeyEvent::KeyEvent(const QKeyEvent& event) { key = event.key(); + text = event.text(); isShifted = event.modifiers().testFlag(Qt::ShiftModifier); - isMeta = event.modifiers().testFlag(Qt::ControlModifier); + isMeta = event.modifiers().testFlag(Qt::MetaModifier); + isControl = event.modifiers().testFlag(Qt::ControlModifier); + isAlt = event.modifiers().testFlag(Qt::AltModifier); + isKeypad = event.modifiers().testFlag(Qt::KeypadModifier); isValid = true; + + // handle special text for special characters... + if (key == Qt::Key_F1) { + text = "F1"; + } else if (key == Qt::Key_F2) { + text = "F2"; + } else if (key == Qt::Key_F3) { + text = "F3"; + } else if (key == Qt::Key_F4) { + text = "F4"; + } else if (key == Qt::Key_F5) { + text = "F5"; + } else if (key == Qt::Key_F6) { + text = "F6"; + } else if (key == Qt::Key_F7) { + text = "F7"; + } else if (key == Qt::Key_F8) { + text = "F8"; + } else if (key == Qt::Key_F9) { + text = "F9"; + } else if (key == Qt::Key_F10) { + text = "F10"; + } else if (key == Qt::Key_F11) { + text = "F11"; + } else if (key == Qt::Key_F12) { + text = "F12"; + } else if (key == Qt::Key_Up) { + text = "UP"; + } else if (key == Qt::Key_Down) { + text = "DOWN"; + } else if (key == Qt::Key_Left) { + text = "LEFT"; + } else if (key == Qt::Key_Right) { + text = "RIGHT"; + } else if (key == Qt::Key_Escape) { + text = "ESC"; + } else if (key == Qt::Key_Tab) { + text = "TAB"; + } else if (key == Qt::Key_Delete) { + text = "DELETE"; + } else if (key == Qt::Key_Backspace) { + text = "BACKSPACE"; + } } MouseEvent::MouseEvent(const QMouseEvent& event) { @@ -65,16 +115,113 @@ void registerEventTypes(QScriptEngine* engine) { QScriptValue keyEventToScriptValue(QScriptEngine* engine, const KeyEvent& event) { QScriptValue obj = engine->newObject(); obj.setProperty("key", event.key); + obj.setProperty("text", event.text); obj.setProperty("isShifted", event.isShifted); obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); + obj.setProperty("isKeypad", event.isKeypad); return obj; } void keyEventFromScriptValue(const QScriptValue &object, KeyEvent& event) { - event.key = object.property("key").toVariant().toInt(); - event.isShifted = object.property("isShifted").toVariant().toBool(); + + event.isValid = false; // assume the worst event.isMeta = object.property("isMeta").toVariant().toBool(); - event.isValid = object.property("key").isValid(); + event.isControl = object.property("isControl").toVariant().toBool(); + event.isAlt = object.property("isAlt").toVariant().toBool(); + event.isKeypad = object.property("isKeypad").toVariant().toBool(); + + QScriptValue key = object.property("key"); + if (key.isValid()) { + event.key = key.toVariant().toInt(); + event.text = QString(QChar(event.key)); + event.isValid = true; + } else { + QScriptValue text = object.property("text"); + if (text.isValid()) { + event.text = object.property("text").toVariant().toString(); + + // if the text is a special command, then map it here... + // TODO: come up with more elegant solution here, a map? is there a Qt function that gives nice names for keys? + if (event.text.toUpper() == "F1") { + event.key = Qt::Key_F1; + } else if (event.text.toUpper() == "F2") { + event.key = Qt::Key_F2; + } else if (event.text.toUpper() == "F3") { + event.key = Qt::Key_F3; + } else if (event.text.toUpper() == "F4") { + event.key = Qt::Key_F4; + } else if (event.text.toUpper() == "F5") { + event.key = Qt::Key_F5; + } else if (event.text.toUpper() == "F6") { + event.key = Qt::Key_F6; + } else if (event.text.toUpper() == "F7") { + event.key = Qt::Key_F7; + } else if (event.text.toUpper() == "F8") { + event.key = Qt::Key_F8; + } else if (event.text.toUpper() == "F9") { + event.key = Qt::Key_F9; + } else if (event.text.toUpper() == "F10") { + event.key = Qt::Key_F10; + } else if (event.text.toUpper() == "F11") { + event.key = Qt::Key_F11; + } else if (event.text.toUpper() == "F12") { + event.key = Qt::Key_F12; + } else if (event.text.toUpper() == "UP") { + event.key = Qt::Key_Up; + event.isKeypad = true; + } else if (event.text.toUpper() == "DOWN") { + event.key = Qt::Key_Down; + event.isKeypad = true; + } else if (event.text.toUpper() == "LEFT") { + event.key = Qt::Key_Left; + event.isKeypad = true; + } else if (event.text.toUpper() == "RIGHT") { + event.key = Qt::Key_Right; + event.isKeypad = true; + } else if (event.text.toUpper() == "ESC") { + event.key = Qt::Key_Escape; + } else if (event.text.toUpper() == "TAB") { + event.key = Qt::Key_Tab; + } else if (event.text.toUpper() == "DELETE") { + event.key = Qt::Key_Delete; + } else if (event.text.toUpper() == "BACKSPACE") { + event.key = Qt::Key_Backspace; + } else { + event.key = event.text.at(0).unicode(); + } + event.isValid = true; + } + } + + QScriptValue isShifted = object.property("isShifted"); + if (isShifted.isValid()) { + event.isShifted = isShifted.toVariant().toBool(); + } else { + // if no isShifted was included, get it from the text + QChar character = event.text.at(0); + if (character.isLetter() && character.isUpper()) { + event.isShifted = true; + } else { + // if it's a symbol, then attempt to detect shifted-ness + if (QString("~!@#$%^&*()_+{}|:\"<>?").contains(character)) { + event.isShifted = true; + } + } + } + + + const bool wantDebug = false; + if (wantDebug) { + qDebug() << "event.key=" << event.key + << " event.text=" << event.text + << " event.isShifted=" << event.isShifted + << " event.isControl=" << event.isControl + << " event.isMeta=" << event.isMeta + << " event.isAlt=" << event.isAlt + << " event.isKeypad=" << event.isKeypad; + } } QScriptValue mouseEventToScriptValue(QScriptEngine* engine, const MouseEvent& event) { diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index c3764b2619..81cba03cea 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -24,10 +24,19 @@ public: KeyEvent(); KeyEvent(const QKeyEvent& event); inline bool operator==(const KeyEvent& other) const { - return other.key == key && other.isShifted == isShifted && other.isMeta == isMeta; } + return other.key == key + && other.isShifted == isShifted + && other.isControl == isControl + && other.isMeta == isMeta + && other.isAlt == isAlt + && other.isKeypad == isKeypad; } int key; + QString text; bool isShifted; + bool isControl; bool isMeta; + bool isAlt; + bool isKeypad; bool isValid; }; From 181670f5d7bca20397bb9255c2ec346f621119c7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 30 Jan 2014 12:53:02 -0800 Subject: [PATCH 11/46] Fixes for parsing FBX text encoding. --- interface/src/renderer/FBXReader.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 8a7f839b70..1a5171d100 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -170,6 +170,7 @@ public: const QByteArray& getDatum() const { return _datum; } void pushBackToken(int token) { _pushedBackToken = token; } + void ungetChar(char ch) { _device->ungetChar(ch); } private: @@ -221,7 +222,7 @@ int Tokenizer::nextToken() { _datum.append(ch); while (_device->getChar(&ch)) { if (QChar(ch).isSpace() || ch == ';' || ch == ':' || ch == '{' || ch == '}' || ch == ',' || ch == '\"') { - _device->ungetChar(ch); // read until we encounter a special character, then replace it + ungetChar(ch); // read until we encounter a special character, then replace it break; } _datum.append(ch); @@ -257,9 +258,17 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) { expectingDatum = true; } else if (token == Tokenizer::DATUM_TOKEN && expectingDatum) { - node.properties.append(tokenizer.getDatum()); - expectingDatum = false; - + QByteArray datum = tokenizer.getDatum(); + if ((token = tokenizer.nextToken()) == ':') { + tokenizer.ungetChar(':'); + tokenizer.pushBackToken(Tokenizer::DATUM_TOKEN); + return node; + + } else { + tokenizer.pushBackToken(token); + node.properties.append(datum); + expectingDatum = false; + } } else { tokenizer.pushBackToken(token); return node; @@ -377,6 +386,9 @@ glm::mat4 createMat4(const QVector& doubleVector) { } QVector getIntVector(const QVariantList& properties, int index) { + if (index >= properties.size()) { + return QVector(); + } QVector vector = properties.at(index).value >(); if (!vector.isEmpty()) { return vector; @@ -388,6 +400,9 @@ QVector getIntVector(const QVariantList& properties, int index) { } QVector getDoubleVector(const QVariantList& properties, int index) { + if (index >= properties.size()) { + return QVector(); + } QVector vector = properties.at(index).value >(); if (!vector.isEmpty()) { return vector; From d2464d89e3ea6d33b4492b16d94d957577b49eda Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 30 Jan 2014 22:23:31 +0100 Subject: [PATCH 12/46] #19493 - @ function can jump to locations as well as avatars --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 89 ++++++++++++++++++++++++++--------- interface/src/Menu.h | 5 +- 3 files changed, 71 insertions(+), 25 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2efcd5b121..f420b2be45 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1093,7 +1093,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _swatch.handleEvent(event->key(), Menu::getInstance()->isOptionChecked(MenuOption::VoxelGetColorMode)); break; case Qt::Key_At: - Menu::getInstance()->goToUser(); + Menu::getInstance()->goTo(); break; default: event->ignore(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8fd268938e..67eaa8782c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -116,10 +116,10 @@ Menu::Menu() : this, SLOT(goToLocation())); addActionToQMenuAndActionHash(fileMenu, - MenuOption::GoToUser, + MenuOption::GoTo, Qt::Key_At, this, - SLOT(goToUser())); + SLOT(goTo())); addDisabledActionAndSeparator(fileMenu, "Settings"); @@ -910,6 +910,60 @@ void Menu::goToDomain() { sendFakeEnterEvent(); } +void Menu::goTo() { + + QInputDialog gotoDialog(Application::getInstance()->getWindow()); + gotoDialog.setWindowTitle("Go to"); + gotoDialog.setLabelText("Destination:"); + QString destination = Application::getInstance()->getProfile()->getUsername(); + gotoDialog.setTextValue(destination); + gotoDialog.setWindowFlags(Qt::Sheet); + gotoDialog.resize(gotoDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, gotoDialog.size().height()); + + int dialogReturn = gotoDialog.exec(); + if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) { + + destination = gotoDialog.textValue(); + + QStringList coordinateItems = destination.split(QRegExp("_|,"), QString::SkipEmptyParts); + + const int NUMBER_OF_COORDINATE_ITEMS = 3; + const int X_ITEM = 0; + const int Y_ITEM = 1; + const int Z_ITEM = 2; + if (coordinateItems.size() == NUMBER_OF_COORDINATE_ITEMS) { + + double x = replaceLastOccurrence('-', '.', coordinateItems[X_ITEM].trimmed()).toDouble(); + double y = replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM].trimmed()).toDouble(); + double z = replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM].trimmed()).toDouble(); + + glm::vec3 newAvatarPos(x, y, z); + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + glm::vec3 avatarPos = myAvatar->getPosition(); + if (newAvatarPos != avatarPos) { + // send a node kill request, indicating to other clients that they should play the "disappeared" effect + MyAvatar::sendKillAvatar(); + + qDebug("Going To Location: %f, %f, %f...", x, y, z); + myAvatar->setPosition(newAvatarPos); + } + + } else { + // there's a username entered by the user, make a request to the data-server + DataServerClient::getValuesForKeysAndUserString( + QStringList() + << DataServerKey::Domain + << DataServerKey::Position + << DataServerKey::Orientation, + destination, Application::getInstance()->getProfile()); + + } + } + + sendFakeEnterEvent(); +} + void Menu::goToLocation() { MyAvatar* myAvatar = Application::getInstance()->getAvatar(); glm::vec3 avatarPos = myAvatar->getPosition(); @@ -954,26 +1008,6 @@ void Menu::goToLocation() { sendFakeEnterEvent(); } -void Menu::goToUser() { - QInputDialog userDialog(Application::getInstance()->getWindow()); - userDialog.setWindowTitle("Go to User"); - userDialog.setLabelText("Destination user:"); - QString username = Application::getInstance()->getProfile()->getUsername(); - userDialog.setTextValue(username); - userDialog.setWindowFlags(Qt::Sheet); - userDialog.resize(userDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, userDialog.size().height()); - - int dialogReturn = userDialog.exec(); - if (dialogReturn == QDialog::Accepted && !userDialog.textValue().isEmpty()) { - // there's a username entered by the user, make a request to the data-server - DataServerClient::getValuesForKeysAndUserString( - QStringList() << DataServerKey::Domain << DataServerKey::Position << DataServerKey::Orientation, - userDialog.textValue(), Application::getInstance()->getProfile()); - } - - sendFakeEnterEvent(); -} - void Menu::pasteToVoxel() { QInputDialog pasteToOctalCodeDialog(Application::getInstance()->getWindow()); pasteToOctalCodeDialog.setWindowTitle("Paste to Voxel"); @@ -1137,3 +1171,14 @@ void Menu::updateFrustumRenderModeAction() { } } +QString Menu::replaceLastOccurrence(QChar search, QChar replace, QString string) { + int lastIndex; + lastIndex = string.lastIndexOf(search); + if (lastIndex > 0) { + lastIndex = string.lastIndexOf(search); + string.replace(lastIndex, 1, replace); + } + + return string; +} + diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 03149ce07c..5e49ca6fd1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -92,7 +92,7 @@ public slots: void saveSettings(QSettings* settings = NULL); void importSettings(); void exportSettings(); - void goToUser(); + void goTo(); void pasteToVoxel(); private slots: @@ -152,6 +152,7 @@ private: QAction* _useVoxelShader; int _maxVoxelPacketsPerSecond; QMenu* _activeScriptsMenu; + QString replaceLastOccurrence(QChar search, QChar replace, QString string); }; namespace MenuOption { @@ -209,7 +210,7 @@ namespace MenuOption { const QString GlowMode = "Cycle Glow Mode"; const QString GoToDomain = "Go To Domain..."; const QString GoToLocation = "Go To Location..."; - const QString GoToUser = "Go To User..."; + const QString GoTo = "Go To..."; const QString ImportVoxels = "Import Voxels"; const QString ImportVoxelsClipboard = "Import Voxels to Clipboard"; const QString IncreaseAvatarSize = "Increase Avatar Size"; From 78d9b798056044d379adca595ab8a08716a1fba4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 30 Jan 2014 13:24:30 -0800 Subject: [PATCH 13/46] Another fix for Blender exports. Closes #1762. --- interface/src/renderer/FBXReader.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 1a5171d100..d128206c80 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1121,6 +1121,11 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QVector modelIDs; QSet remainingModels; for (QHash::const_iterator model = models.constBegin(); model != models.constEnd(); model++) { + // make sure the parent is in the child map + QString parent = parentMap.value(model.key()); + if (!childMap.contains(parent, model.key())) { + childMap.insert(parent, model.key()); + } remainingModels.insert(model.key()); } while (!remainingModels.isEmpty()) { From 356222ba15dd17b3a3d01b14f1e791cebcdd5778 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 14:33:36 -0800 Subject: [PATCH 14/46] removal of persistence in DS for static assignments --- domain-server/src/DomainServer.cpp | 590 +++++++++++----------------- domain-server/src/DomainServer.h | 41 +- libraries/shared/src/Assignment.cpp | 2 +- 3 files changed, 252 insertions(+), 381 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 603041be54..f191fdd3ac 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -8,9 +8,11 @@ #include +#include #include #include #include +#include #include #include @@ -27,64 +29,37 @@ const char* VOXEL_SERVER_CONFIG = "voxelServerConfig"; const char* PARTICLE_SERVER_CONFIG = "particleServerConfig"; const char* METAVOXEL_SERVER_CONFIG = "metavoxelServerConfig"; -void signalhandler(int sig){ - if (sig == SIGINT) { - qApp->quit(); - } -} - const quint16 DOMAIN_SERVER_HTTP_PORT = 8080; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), + _staticAssignmentHash(), _assignmentQueue(), - _staticAssignmentFile(QString("%1/config.ds").arg(QCoreApplication::applicationDirPath())), - _staticAssignmentFileData(NULL), - _voxelServerConfig(NULL), - _metavoxelServerConfig(NULL), _hasCompletedRestartHold(false) { - signal(SIGINT, signalhandler); - const char CUSTOM_PORT_OPTION[] = "-p"; const char* customPortString = getCmdOption(argc, (const char**) argv, CUSTOM_PORT_OPTION); unsigned short domainServerPort = customPortString ? atoi(customPortString) : DEFAULT_DOMAIN_SERVER_PORT; - - const char CONFIG_FILE_OPTION[] = "-c"; - const char* configFilePath = getCmdOption(argc, (const char**) argv, CONFIG_FILE_OPTION); - - if (!readConfigFile(configFilePath)) { - QByteArray voxelConfigOption = QString("--%1").arg(VOXEL_SERVER_CONFIG).toLocal8Bit(); - _voxelServerConfig = getCmdOption(argc, (const char**) argv, voxelConfigOption.constData()); - - QByteArray particleConfigOption = QString("--%1").arg(PARTICLE_SERVER_CONFIG).toLocal8Bit(); - _particleServerConfig = getCmdOption(argc, (const char**) argv, particleConfigOption.constData()); - - QByteArray metavoxelConfigOption = QString("--%1").arg(METAVOXEL_SERVER_CONFIG).toLocal8Bit(); - _metavoxelServerConfig = getCmdOption(argc, (const char**) argv, metavoxelConfigOption.constData()); + + QStringList argumentList = arguments(); + int argumentIndex = 0; + + QSet parsedTypes(QSet() << Assignment::AgentType); + parseCommandLineTypeConfigs(argumentList, parsedTypes); + + const QString CONFIG_FILE_OPTION = "--configFile"; + if ((argumentIndex = argumentList.indexOf(CONFIG_FILE_OPTION)) != -1) { + QString configFilePath = argumentList.value(argumentIndex + 1); + readConfigFile(configFilePath, parsedTypes); } + + populateDefaultStaticAssignmentsExcludingTypes(parsedTypes); NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), this, SLOT(nodeKilled(SharedNodePointer))); - if (!_staticAssignmentFile.exists() || _voxelServerConfig) { - - if (_voxelServerConfig) { - // we have a new VS config, clear the existing file to start fresh - _staticAssignmentFile.remove(); - } - - prepopulateStaticAssignmentFile(); - } - - _staticAssignmentFile.open(QIODevice::ReadWrite); - - _staticAssignmentFileData = _staticAssignmentFile.map(0, _staticAssignmentFile.size()); - - _staticAssignments = (Assignment*) _staticAssignmentFileData; - QTimer* silentNodeTimer = new QTimer(this); connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); @@ -93,8 +68,145 @@ DomainServer::DomainServer(int argc, char* argv[]) : // fire a single shot timer to add static assignments back into the queue after a restart QTimer::singleShot(RESTART_HOLD_TIME_MSECS, this, SLOT(addStaticAssignmentsBackToQueueAfterRestart())); +} - connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup())); +void DomainServer::parseCommandLineTypeConfigs(const QStringList& argumentList, QSet& excludedTypes) { + // check for configs from the command line, these take precedence + const QString CONFIG_TYPE_OPTION = "--configType"; + int clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION); + + // enumerate all CL config overrides and parse them to files + while (clConfigIndex != -1) { + int clConfigType = argumentList.value(clConfigIndex + 1).toInt(); + if (clConfigType < Assignment::AllTypes && !excludedTypes.contains((Assignment::Type) clConfigIndex)) { + Assignment::Type assignmentType = (Assignment::Type) clConfigType; + createStaticAssignmentsForTypeGivenConfigString((Assignment::Type) assignmentType, + argumentList.value(clConfigIndex + 2)); + + excludedTypes.insert(assignmentType); + } + + clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION, clConfigIndex); + } +} + +// Attempts to read configuration from specified path +// returns true on success, false otherwise +void DomainServer::readConfigFile(const QString& path, QSet& excludedTypes) { + if (path.isEmpty()) { + // config file not specified + return; + } + + if (!QFile::exists(path)) { + qWarning("Specified configuration file does not exist!"); + return; + } + + QFile configFile(path); + if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning("Can't open specified configuration file!"); + return; + } else { + qDebug() << "Reading configuration from" << path; + } + + QTextStream configStream(&configFile); + QByteArray configStringByteArray = configStream.readAll().toUtf8(); + QJsonObject configDocObject = QJsonDocument::fromJson(configStringByteArray).object(); + configFile.close(); + + QSet appendedExcludedTypes = excludedTypes; + + foreach (const QString& rootStringValue, configDocObject.keys()) { + int possibleConfigType = rootStringValue.toInt(); + + if (possibleConfigType < Assignment::AllTypes + && !excludedTypes.contains((Assignment::Type) possibleConfigType)) { + // this is an appropriate config type and isn't already in our excluded types + // we are good to parse it + Assignment::Type assignmentType = (Assignment::Type) possibleConfigType; + QString configString = readServerAssignmentConfig(configDocObject, rootStringValue); + createStaticAssignmentsForTypeGivenConfigString(assignmentType, configString); + + excludedTypes.insert(assignmentType); + } + } +} + +// find assignment configurations on the specified node name and json object +// returns a string in the form of its equivalent cmd line params +QString DomainServer::readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName) { + QJsonArray nodeArray = jsonObject[nodeName].toArray(); + + QStringList serverConfig; + foreach (const QJsonValue& childValue, nodeArray) { + QString cmdParams; + QJsonObject childObject = childValue.toObject(); + QStringList keys = childObject.keys(); + for (int i = 0; i < keys.size(); i++) { + QString key = keys[i]; + QString value = childObject[key].toString(); + // both cmd line params and json keys are the same + cmdParams += QString("--%1 %2 ").arg(key, value); + } + serverConfig << cmdParams; + } + + // according to split() calls from DomainServer::prepopulateStaticAssignmentFile + // we shold simply join them with semicolons + return serverConfig.join(';'); +} + +void DomainServer::addStaticAssignmentToAssignmentHash(Assignment* newAssignment) { + qDebug() << "Inserting assignment" << *newAssignment << "to static assignment hash."; + _staticAssignmentHash.insert(newAssignment->getUUID(), SharedAssignmentPointer(newAssignment)); +} + +void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::Type type, const QString& configString) { + // we have a string for config for this type + qDebug() << "Parsing command line config for assignment type" << type; + + QString multiConfig(configString); + QStringList multiConfigList = multiConfig.split(";"); + + // read each config to a payload for this type of assignment + for (int i = 0; i < multiConfigList.size(); i++) { + QString config = multiConfigList.at(i); + + qDebug("type %d config[%d] = %s", type, i, config.toLocal8Bit().constData()); + + // Now, parse the config to check for a pool + const QString ASSIGNMENT_CONFIG_POOL_OPTION = "--pool"; + QString assignmentPool; + + int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION); + + if (poolIndex >= 0) { + int spaceBeforePoolIndex = config.indexOf(' ', poolIndex); + int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex); + + assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex); + } + + Assignment* configAssignment = new Assignment(Assignment::CreateCommand, type, assignmentPool); + + configAssignment->setPayload(config.toUtf8()); + + addStaticAssignmentToAssignmentHash(configAssignment); + } +} + +void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet& excludedTypes) { + // enumerate over all assignment types and see if we've already excluded it + for (Assignment::Type defaultedType = Assignment::AudioMixerType; defaultedType != Assignment::AllTypes; defaultedType++) { + if (!excludedTypes.contains(defaultedType)) { + // type has not been set from a command line or config file config, use the default + // by clearing whatever exists and writing a single default assignment with no payload + Assignment* newAssignment = new Assignment(Assignment::CreateCommand, defaultedType); + addStaticAssignmentToAssignmentHash(newAssignment); + } + } } void DomainServer::readAvailableDatagrams() { @@ -147,13 +259,11 @@ void DomainServer::readAvailableDatagrams() { << NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer << NodeType::MetavoxelServer; - Assignment* matchingStaticAssignment = NULL; + SharedAssignmentPointer matchingStaticAssignment; if (!STATICALLY_ASSIGNED_NODES.contains(nodeType) - || ((matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) - || checkInWithUUIDMatchesExistingNode(nodePublicAddress, - nodeLocalAddress, - nodeUUID))) + || (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) + || checkInWithUUIDMatchesExistingNode(nodePublicAddress, nodeLocalAddress, nodeUUID)) { SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID, nodeType, @@ -166,19 +276,13 @@ void DomainServer::readAvailableDatagrams() { if (matchingStaticAssignment) { // this was a newly added node with a matching static assignment + // remove the matching assignment from the assignment queue so we don't take the next check in + // (if it exists) if (_hasCompletedRestartHold) { - // remove the matching assignment from the assignment queue so we don't take the next check in - removeAssignmentFromQueue(matchingStaticAssignment); + removeMatchingAssignmentFromQueue(matchingStaticAssignment); } - - // set the linked data for this node to a copy of the matching assignment - // so we can re-queue it should the node die - Assignment* nodeCopyOfMatchingAssignment = new Assignment(*matchingStaticAssignment); - - checkInNode->setLinkedData(nodeCopyOfMatchingAssignment); } - quint8 numInterestTypes = 0; packetStream >> numInterestTypes; @@ -216,7 +320,7 @@ void DomainServer::readAvailableDatagrams() { qDebug("Received a request for assignment type %i from %s.", requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString())); - Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); + SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); if (assignmentToDeploy) { // give this assignment out, either the type matches or the requestor said they will take any @@ -224,15 +328,10 @@ void DomainServer::readAvailableDatagrams() { QDataStream assignmentStream(&assignmentPacket, QIODevice::Append); - assignmentStream << *assignmentToDeploy; + assignmentStream << assignmentToDeploy; nodeList->getNodeSocket().writeDatagram(assignmentPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); - - if (assignmentToDeploy->getNumberOfInstances() == 0) { - // there are no more instances of this script to send out, delete it - delete assignmentToDeploy; - } } } else { @@ -280,70 +379,6 @@ QJsonObject jsonObjectForNode(Node* node) { return nodeJson; } -// Attempts to read configuration from specified path -// returns true on success, false otherwise -bool DomainServer::readConfigFile(const char* path) { - if (!path) { - // config file not specified - return false; - } - - if (!QFile::exists(path)) { - qWarning("Specified configuration file does not exist!\n"); - return false; - } - - QFile configFile(path); - if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning("Can't open specified configuration file!\n"); - return false; - } else { - qDebug("Reading configuration from %s\n", path); - } - QTextStream configStream(&configFile); - QByteArray configStringByteArray = configStream.readAll().toUtf8(); - QJsonObject configDocObject = QJsonDocument::fromJson(configStringByteArray).object(); - configFile.close(); - - QString voxelServerConfig = readServerAssignmentConfig(configDocObject, VOXEL_SERVER_CONFIG); - _voxelServerConfig = new char[strlen(voxelServerConfig.toLocal8Bit().constData()) +1]; - _voxelServerConfig = strcpy((char *) _voxelServerConfig, voxelServerConfig.toLocal8Bit().constData() + '\0'); - - QString particleServerConfig = readServerAssignmentConfig(configDocObject, PARTICLE_SERVER_CONFIG); - _particleServerConfig = new char[strlen(particleServerConfig.toLocal8Bit().constData()) +1]; - _particleServerConfig = strcpy((char *) _particleServerConfig, particleServerConfig.toLocal8Bit().constData() + '\0'); - - QString metavoxelServerConfig = readServerAssignmentConfig(configDocObject, METAVOXEL_SERVER_CONFIG); - _metavoxelServerConfig = new char[strlen(metavoxelServerConfig.toLocal8Bit().constData()) +1]; - _metavoxelServerConfig = strcpy((char *) _metavoxelServerConfig, metavoxelServerConfig.toLocal8Bit().constData() + '\0'); - - return true; -} - -// find assignment configurations on the specified node name and json object -// returns a string in the form of its equivalent cmd line params -QString DomainServer::readServerAssignmentConfig(QJsonObject jsonObject, const char* nodeName) { - QJsonArray nodeArray = jsonObject[nodeName].toArray(); - - QStringList serverConfig; - foreach (const QJsonValue & childValue, nodeArray) { - QString cmdParams; - QJsonObject childObject = childValue.toObject(); - QStringList keys = childObject.keys(); - for (int i = 0; i < keys.size(); i++) { - QString key = keys[i]; - QString value = childObject[key].toString(); - // both cmd line params and json keys are the same - cmdParams += QString("--%1 %2 ").arg(key, value); - } - serverConfig << cmdParams; - } - - // according to split() calls from DomainServer::prepopulateStaticAssignmentFile - // we shold simply join them with semicolons - return serverConfig.join(';'); -} - bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& path) { const QString JSON_MIME_TYPE = "application/json"; @@ -372,24 +407,19 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& QJsonObject queuedAssignmentsJSON; // add the queued but unfilled assignments to the json - std::deque::iterator assignment = _assignmentQueue.begin(); - - while (assignment != _assignmentQueue.end()) { + foreach(const SharedAssignmentPointer& assignment, _assignmentQueue) { QJsonObject queuedAssignmentJSON; - QString uuidString = uuidStringWithoutCurlyBraces((*assignment)->getUUID()); - queuedAssignmentJSON[JSON_KEY_TYPE] = QString((*assignment)->getTypeName()); + QString uuidString = uuidStringWithoutCurlyBraces(assignment->getUUID()); + queuedAssignmentJSON[JSON_KEY_TYPE] = QString(assignment->getTypeName()); // if the assignment has a pool, add it - if (!(*assignment)->getPool().isEmpty()) { - queuedAssignmentJSON[JSON_KEY_POOL] = (*assignment)->getPool(); + if (!assignment->getPool().isEmpty()) { + queuedAssignmentJSON[JSON_KEY_POOL] = assignment->getPool(); } // add this queued assignment to the JSON queuedAssignmentsJSON[uuidString] = queuedAssignmentJSON; - - // push forward the iterator to check the next assignment - assignment++; } assignmentJSON["queued"] = queuedAssignmentsJSON; @@ -427,11 +457,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // this is a script upload - ask the HTTPConnection to parse the form data QList formData = connection->parseFormData(); - // create an assignment for this saved script, for now make it local only - Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand, - Assignment::AgentType, - NULL, - Assignment::LocalLocation); + // create an assignment for this saved script + Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType); // check how many instances of this assignment the user wants by checking the ASSIGNMENT-INSTANCES header const QString ASSIGNMENT_INSTANCES_HEADER = "ASSIGNMENT-INSTANCES"; @@ -465,8 +492,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& connection->respond(HTTPConnection::StatusCode200); // add the script assigment to the assignment queue - // lock the assignment queue mutex since we're operating on a different thread than DS main - _assignmentQueue.push_back(scriptAssignment); + _assignmentQueue.enqueue(SharedAssignmentPointer(scriptAssignment)); } } else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) { if (path.startsWith(URI_NODE)) { @@ -501,228 +527,99 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& return false; } -void DomainServer::addReleasedAssignmentBackToQueue(Assignment* releasedAssignment) { - qDebug() << "Adding assignment" << *releasedAssignment << " back to queue."; - - // find this assignment in the static file - for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { - if (_staticAssignments[i].getUUID() == releasedAssignment->getUUID()) { - // reset the UUID on the static assignment - _staticAssignments[i].resetUUID(); - - // put this assignment back in the queue so it goes out - _assignmentQueue.push_back(&_staticAssignments[i]); - - } else if (_staticAssignments[i].getUUID().isNull()) { - // we are at the blank part of the static assignments - break out - break; - } - } +void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment) { + QUuid oldUUID = assignment->getUUID(); + assignment->resetUUID(); + + qDebug() << "Reset UUID for assignment -" << *assignment.data() << "- and added to queue. Old UUID was" + << uuidStringWithoutCurlyBraces( oldUUID); + _assignmentQueue.enqueue(assignment); } void DomainServer::nodeKilled(SharedNodePointer node) { - // if this node has linked data it was from an assignment - if (node->getLinkedData()) { - Assignment* nodeAssignment = (Assignment*) node->getLinkedData(); - - addReleasedAssignmentBackToQueue(nodeAssignment); + // if this node's UUID matches a static assignment we need to throw it back in the assignment queue + SharedAssignmentPointer matchedAssignment = _staticAssignmentHash.value(node->getUUID()); + if (matchedAssignment) { + refreshStaticAssignmentAndAddToQueue(matchedAssignment); } } -void DomainServer::prepopulateStaticAssignmentFile() { - int numFreshStaticAssignments = 0; - - // write a fresh static assignment array to file - - Assignment freshStaticAssignments[MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS]; - - // pre-populate the first static assignment list with assignments for root AuM, AvM, VS - freshStaticAssignments[numFreshStaticAssignments++] = Assignment(Assignment::CreateCommand, Assignment::AudioMixerType); - freshStaticAssignments[numFreshStaticAssignments++] = Assignment(Assignment::CreateCommand, Assignment::AvatarMixerType); - - // Handle Domain/Voxel Server configuration command line arguments - if (_voxelServerConfig) { - qDebug("Reading Voxel Server Configuration."); - qDebug() << "config: " << _voxelServerConfig; - - QString multiConfig((const char*) _voxelServerConfig); - QStringList multiConfigList = multiConfig.split(";"); - - // read each config to a payload for a VS assignment - for (int i = 0; i < multiConfigList.size(); i++) { - QString config = multiConfigList.at(i); - - qDebug("config[%d]=%s", i, config.toLocal8Bit().constData()); - - // Now, parse the config to check for a pool - const char ASSIGNMENT_CONFIG_POOL_OPTION[] = "--pool"; - QString assignmentPool; - - int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION); - - if (poolIndex >= 0) { - int spaceBeforePoolIndex = config.indexOf(' ', poolIndex); - int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex); - - assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex); - qDebug() << "The pool for this voxel-assignment is" << assignmentPool; - } - - Assignment voxelServerAssignment(Assignment::CreateCommand, - Assignment::VoxelServerType, - assignmentPool); - - voxelServerAssignment.setPayload(config.toUtf8()); - - freshStaticAssignments[numFreshStaticAssignments++] = voxelServerAssignment; - } - } else { - Assignment rootVoxelServerAssignment(Assignment::CreateCommand, Assignment::VoxelServerType); - freshStaticAssignments[numFreshStaticAssignments++] = rootVoxelServerAssignment; - } - - // Handle Domain/Particle Server configuration command line arguments - if (_particleServerConfig) { - qDebug("Reading Particle Server Configuration."); - qDebug() << "config: " << _particleServerConfig; - - QString multiConfig((const char*) _particleServerConfig); - QStringList multiConfigList = multiConfig.split(";"); - - // read each config to a payload for a VS assignment - for (int i = 0; i < multiConfigList.size(); i++) { - QString config = multiConfigList.at(i); - - qDebug("config[%d]=%s", i, config.toLocal8Bit().constData()); - - // Now, parse the config to check for a pool - const char ASSIGNMENT_CONFIG_POOL_OPTION[] = "--pool"; - QString assignmentPool; - - int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION); - - if (poolIndex >= 0) { - int spaceBeforePoolIndex = config.indexOf(' ', poolIndex); - int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex); - - assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex); - qDebug() << "The pool for this particle-assignment is" << assignmentPool; - } - - Assignment particleServerAssignment(Assignment::CreateCommand, - Assignment::ParticleServerType, - assignmentPool); - - particleServerAssignment.setPayload(config.toLocal8Bit()); - - freshStaticAssignments[numFreshStaticAssignments++] = particleServerAssignment; - } - } else { - Assignment rootParticleServerAssignment(Assignment::CreateCommand, Assignment::ParticleServerType); - freshStaticAssignments[numFreshStaticAssignments++] = rootParticleServerAssignment; - } - - // handle metavoxel configuration command line argument - Assignment& metavoxelAssignment = (freshStaticAssignments[numFreshStaticAssignments++] = - Assignment(Assignment::CreateCommand, Assignment::MetavoxelServerType)); - if (_metavoxelServerConfig) { - metavoxelAssignment.setPayload(QByteArray(_metavoxelServerConfig)); - } - - qDebug() << "Adding" << numFreshStaticAssignments << "static assignments to fresh file."; - - _staticAssignmentFile.open(QIODevice::WriteOnly); - _staticAssignmentFile.write((char*) &freshStaticAssignments, sizeof(freshStaticAssignments)); - _staticAssignmentFile.resize(MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS * sizeof(Assignment)); - _staticAssignmentFile.close(); -} - -Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) { - // pull the UUID passed with the check in - +SharedAssignmentPointer DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) { if (_hasCompletedRestartHold) { - // iterate the assignment queue to check for a match - std::deque::iterator assignment = _assignmentQueue.begin(); - while (assignment != _assignmentQueue.end()) { - if ((*assignment)->getUUID() == checkInUUID) { - // return the matched assignment - return *assignment; - } else { - // no match, push deque iterator forwards - assignment++; + // look for a match in the assignment hash + + QQueue::iterator i = _assignmentQueue.begin(); + + while (i != _assignmentQueue.end()) { + if (i->data()->getType() == nodeType && i->data()->getUUID() == checkInUUID) { + return _assignmentQueue.takeAt(i - _assignmentQueue.begin()); } } - } else { - for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { - if (_staticAssignments[i].getUUID() == checkInUUID) { - // return matched assignment - return &_staticAssignments[i]; - } else if (_staticAssignments[i].getUUID().isNull()) { - // end of static assignments, no match - return NULL - return NULL; - } + SharedAssignmentPointer matchingStaticAssignment = _staticAssignmentHash.value(checkInUUID); + if (matchingStaticAssignment && matchingStaticAssignment->getType() == nodeType) { + return matchingStaticAssignment; } } - return NULL; + return SharedAssignmentPointer(); } -Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssignment) { +SharedAssignmentPointer DomainServer::deployableAssignmentForRequest(const Assignment& requestAssignment) { // this is an unassigned client talking to us directly for an assignment // go through our queue and see if there are any assignments to give out - std::deque::iterator assignment = _assignmentQueue.begin(); + QQueue::iterator sharedAssignment = _assignmentQueue.begin(); - while (assignment != _assignmentQueue.end()) { + while (sharedAssignment != _assignmentQueue.end()) { + Assignment* assignment = sharedAssignment->data(); bool requestIsAllTypes = requestAssignment.getType() == Assignment::AllTypes; - bool assignmentTypesMatch = (*assignment)->getType() == requestAssignment.getType(); - bool nietherHasPool = (*assignment)->getPool().isEmpty() && requestAssignment.getPool().isEmpty(); - bool assignmentPoolsMatch = (*assignment)->getPool() == requestAssignment.getPool(); + bool assignmentTypesMatch = assignment->getType() == requestAssignment.getType(); + bool nietherHasPool = assignment->getPool().isEmpty() && requestAssignment.getPool().isEmpty(); + bool assignmentPoolsMatch = assignment->getPool() == requestAssignment.getPool(); if ((requestIsAllTypes || assignmentTypesMatch) && (nietherHasPool || assignmentPoolsMatch)) { - Assignment* deployableAssignment = *assignment; - - if ((*assignment)->getType() == Assignment::AgentType) { + if (assignment->getType() == Assignment::AgentType) { // if there is more than one instance to send out, simply decrease the number of instances - if ((*assignment)->getNumberOfInstances() == 1) { - _assignmentQueue.erase(assignment); + if (assignment->getNumberOfInstances() == 1) { + return _assignmentQueue.takeAt(sharedAssignment - _assignmentQueue.begin()); + } else { + assignment->decrementNumberOfInstances(); + return *sharedAssignment; } - deployableAssignment->decrementNumberOfInstances(); - } else { // remove the assignment from the queue - _assignmentQueue.erase(assignment); + SharedAssignmentPointer deployableAssignment = _assignmentQueue.takeAt(sharedAssignment + - _assignmentQueue.begin()); // until we get a check-in from that GUID // put assignment back in queue but stick it at the back so the others have a chance to go out - _assignmentQueue.push_back(deployableAssignment); + _assignmentQueue.enqueue(deployableAssignment); + + // stop looping, we've handed out an assignment + return deployableAssignment; } - - // stop looping, we've handed out an assignment - return deployableAssignment; } else { // push forward the iterator to check the next assignment - assignment++; + ++sharedAssignment; } } - return NULL; + return SharedAssignmentPointer(); } -void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) { - - std::deque::iterator assignment = _assignmentQueue.begin(); - - while (assignment != _assignmentQueue.end()) { - if ((*assignment)->getUUID() == removableAssignment->getUUID()) { - _assignmentQueue.erase(assignment); +void DomainServer::removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment) { + QQueue::iterator potentialMatchingAssignment = _assignmentQueue.begin(); + while (potentialMatchingAssignment != _assignmentQueue.end()) { + if (potentialMatchingAssignment->data()->getUUID() == removableAssignment->getUUID()) { + _assignmentQueue.erase(potentialMatchingAssignment); + + // we matched and removed an assignment, bail out break; } else { - // push forward the iterator to check the next assignment - assignment++; + ++potentialMatchingAssignment; } } } @@ -749,43 +646,24 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { _hasCompletedRestartHold = true; // if the domain-server has just restarted, - // check if there are static assignments in the file that we need to - // throw into the assignment queue - - // pull anything in the static assignment file that isn't spoken for and add to the assignment queue - for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { - if (_staticAssignments[i].getUUID().isNull()) { - // reached the end of static assignments, bail - break; - } - + // check if there are static assignments that we need to throw into the assignment queue + QHash::iterator staticAssignment = _staticAssignmentHash.begin(); + while (staticAssignment != _staticAssignmentHash.end()) { + // add any of the un-matched static assignments to the queue bool foundMatchingAssignment = false; - - NodeList* nodeList = NodeList::getInstance(); - + // enumerate the nodes and check if there is one with an attached assignment with matching UUID - foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { - if (node->getLinkedData()) { - Assignment* linkedAssignment = (Assignment*) node->getLinkedData(); - if (linkedAssignment->getUUID() == _staticAssignments[i].getUUID()) { - foundMatchingAssignment = true; - break; - } + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + if (node->getUUID() == staticAssignment->data()->getUUID()) { + foundMatchingAssignment = true; } } - + if (!foundMatchingAssignment) { // this assignment has not been fulfilled - reset the UUID and add it to the assignment queue - _staticAssignments[i].resetUUID(); - - qDebug() << "Adding static assignment to queue -" << _staticAssignments[i]; - - _assignmentQueue.push_back(&_staticAssignments[i]); + refreshStaticAssignmentAndAddToQueue(*staticAssignment); } + + ++staticAssignment; } } - -void DomainServer::cleanup() { - _staticAssignmentFile.unmap(_staticAssignmentFileData); - _staticAssignmentFile.close(); -} diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index ca83436c35..06ae3c2d0e 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -9,17 +9,16 @@ #ifndef __hifi__DomainServer__ #define __hifi__DomainServer__ -#include - #include -#include -#include +#include +#include +#include #include #include #include -const int MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS = 1000; +typedef QSharedPointer SharedAssignmentPointer; class DomainServer : public QCoreApplication, public HTTPRequestHandler { Q_OBJECT @@ -35,36 +34,30 @@ public slots: void nodeKilled(SharedNodePointer node); private: - bool readConfigFile(const char* path); - QString readServerAssignmentConfig(QJsonObject jsonObj, const char* nodeName); - - void prepopulateStaticAssignmentFile(); - Assignment* matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType); - Assignment* deployableAssignmentForRequest(Assignment& requestAssignment); - void removeAssignmentFromQueue(Assignment* removableAssignment); + void parseCommandLineTypeConfigs(const QStringList& argumentList, QSet& excludedTypes); + void readConfigFile(const QString& path, QSet& excludedTypes); + QString readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName); + void addStaticAssignmentToAssignmentHash(Assignment* newAssignment); + void createStaticAssignmentsForTypeGivenConfigString(Assignment::Type type, const QString& configString); + void populateDefaultStaticAssignmentsExcludingTypes(const QSet& excludedTypes); + + SharedAssignmentPointer matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType); + SharedAssignmentPointer deployableAssignmentForRequest(const Assignment& requestAssignment); + void removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment); bool checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, const HifiSockAddr& nodeLocalSocket, const QUuid& checkInUUI); - void addReleasedAssignmentBackToQueue(Assignment* releasedAssignment); + void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment); HTTPManager _HTTPManager; - std::deque _assignmentQueue; - - QFile _staticAssignmentFile; - uchar* _staticAssignmentFileData; - - Assignment* _staticAssignments; - - const char* _voxelServerConfig; - const char* _particleServerConfig; - const char* _metavoxelServerConfig; + QHash _staticAssignmentHash; + QQueue _assignmentQueue; bool _hasCompletedRestartHold; private slots: void readAvailableDatagrams(); void addStaticAssignmentsBackToQueueAfterRestart(); - void cleanup(); }; #endif /* defined(__hifi__DomainServer__) */ diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index f8dcf3edca..a7dd5c36f8 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -144,7 +144,7 @@ const char* Assignment::getTypeName() const { QDebug operator<<(QDebug debug, const Assignment &assignment) { debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) << ", Type: " << assignment.getType(); - return debug.nospace(); + return debug.space(); } QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { From 55049eeb6b358925ca95c36e54cf4a67b2fc7af1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 14:54:52 -0800 Subject: [PATCH 15/46] fix assignment packing and unpacking from DS to AC --- assignment-client/src/AssignmentFactory.cpp | 7 ++- domain-server/src/DomainServer.cpp | 62 ++++++++------------- domain-server/src/DomainServer.h | 3 - 3 files changed, 28 insertions(+), 44 deletions(-) diff --git a/assignment-client/src/AssignmentFactory.cpp b/assignment-client/src/AssignmentFactory.cpp index ef587c9b6d..5bf0417f22 100644 --- a/assignment-client/src/AssignmentFactory.cpp +++ b/assignment-client/src/AssignmentFactory.cpp @@ -19,10 +19,11 @@ #include "metavoxels/MetavoxelServer.h" ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) { - int headerBytes = numBytesForPacketHeader(packet); - + QDataStream packetStream(packet); + packetStream.skipRawData(numBytesForPacketHeader(packet)); + quint8 packedType; - memcpy(&packedType, packet.data() + headerBytes, sizeof(packedType)); + packetStream >> packedType; Assignment::Type unpackedType = (Assignment::Type) packedType; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index f191fdd3ac..0ab75c0088 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -261,9 +261,11 @@ void DomainServer::readAvailableDatagrams() { SharedAssignmentPointer matchingStaticAssignment; + // check if this is a non-statically assigned node, a node that is assigned and checking in for the first time + // or a node that has already checked in and is continuing to report for duty if (!STATICALLY_ASSIGNED_NODES.contains(nodeType) || (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) - || checkInWithUUIDMatchesExistingNode(nodePublicAddress, nodeLocalAddress, nodeUUID)) + || nodeList->getInstance()->nodeWithUUID(nodeUUID)) { SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID, nodeType, @@ -313,29 +315,29 @@ void DomainServer::readAvailableDatagrams() { } } else if (requestType == PacketTypeRequestAssignment) { - if (_assignmentQueue.size() > 0) { - // construct the requested assignment from the packet data - Assignment requestAssignment(receivedPacket); + // construct the requested assignment from the packet data + Assignment requestAssignment(receivedPacket); + + qDebug() << "Received a request for assignment type" << requestAssignment.getType() + << "from" << senderSockAddr; + + SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); + + if (assignmentToDeploy) { + qDebug() << "Deploying assignment -" << *assignmentToDeploy.data() << "- to" << senderSockAddr; - qDebug("Received a request for assignment type %i from %s.", - requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString())); + // give this assignment out, either the type matches or the requestor said they will take any + assignmentPacket.resize(numAssignmentPacketHeaderBytes); - SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); + QDataStream assignmentStream(&assignmentPacket, QIODevice::Append); - if (assignmentToDeploy) { - // give this assignment out, either the type matches or the requestor said they will take any - assignmentPacket.resize(numAssignmentPacketHeaderBytes); - - QDataStream assignmentStream(&assignmentPacket, QIODevice::Append); - - assignmentStream << assignmentToDeploy; - - nodeList->getNodeSocket().writeDatagram(assignmentPacket, - senderSockAddr.getAddress(), senderSockAddr.getPort()); - } + assignmentStream << *assignmentToDeploy.data(); + nodeList->getNodeSocket().writeDatagram(assignmentPacket, + senderSockAddr.getAddress(), senderSockAddr.getPort()); } else { - qDebug() << "Received an invalid assignment request from" << senderSockAddr.getAddress(); + qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType() + << "from" << senderSockAddr; } } } @@ -551,8 +553,10 @@ SharedAssignmentPointer DomainServer::matchingStaticAssignmentForCheckIn(const Q QQueue::iterator i = _assignmentQueue.begin(); while (i != _assignmentQueue.end()) { - if (i->data()->getType() == nodeType && i->data()->getUUID() == checkInUUID) { + if (i->data()->getType() == Assignment::typeForNodeType(nodeType) && i->data()->getUUID() == checkInUUID) { return _assignmentQueue.takeAt(i - _assignmentQueue.begin()); + } else { + ++i; } } } else { @@ -624,24 +628,6 @@ void DomainServer::removeMatchingAssignmentFromQueue(const SharedAssignmentPoint } } -bool DomainServer::checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, - const HifiSockAddr& nodeLocalSocket, - const QUuid& checkInUUID) { - NodeList* nodeList = NodeList::getInstance(); - - foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { - if (node->getLinkedData() - && nodePublicSocket == node->getPublicSocket() - && nodeLocalSocket == node->getLocalSocket() - && node->getUUID() == checkInUUID) { - // this is a matching existing node if the public socket, local socket, and UUID match - return true; - } - } - - return false; -} - void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { _hasCompletedRestartHold = true; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 06ae3c2d0e..60251b3bb4 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -44,9 +44,6 @@ private: SharedAssignmentPointer matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType); SharedAssignmentPointer deployableAssignmentForRequest(const Assignment& requestAssignment); void removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment); - bool checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, - const HifiSockAddr& nodeLocalSocket, - const QUuid& checkInUUI); void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment); HTTPManager _HTTPManager; From 984fb1a5df0674acb9bf51548d662634159e1982 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 15:22:03 -0800 Subject: [PATCH 16/46] fix config parsing from command line and json --- domain-server/src/DomainServer.cpp | 26 +++++++++++++------------- libraries/shared/src/Assignment.cpp | 5 +++++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0ab75c0088..2c1cb55d2e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -82,11 +82,10 @@ void DomainServer::parseCommandLineTypeConfigs(const QStringList& argumentList, Assignment::Type assignmentType = (Assignment::Type) clConfigType; createStaticAssignmentsForTypeGivenConfigString((Assignment::Type) assignmentType, argumentList.value(clConfigIndex + 2)); - excludedTypes.insert(assignmentType); } - clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION, clConfigIndex); + clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION, clConfigIndex + 1); } } @@ -167,28 +166,29 @@ void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::T // we have a string for config for this type qDebug() << "Parsing command line config for assignment type" << type; - QString multiConfig(configString); - QStringList multiConfigList = multiConfig.split(";"); + QStringList multiConfigList = configString.split(";", QString::SkipEmptyParts); + + const QString ASSIGNMENT_CONFIG_POOL_REGEX = "--pool\\s*(\\w+)"; + QRegExp poolRegex(ASSIGNMENT_CONFIG_POOL_REGEX); // read each config to a payload for this type of assignment for (int i = 0; i < multiConfigList.size(); i++) { QString config = multiConfigList.at(i); - qDebug("type %d config[%d] = %s", type, i, config.toLocal8Bit().constData()); - - // Now, parse the config to check for a pool - const QString ASSIGNMENT_CONFIG_POOL_OPTION = "--pool"; + // check the config string for a pool QString assignmentPool; - int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION); + int poolIndex = poolRegex.indexIn(config); - if (poolIndex >= 0) { - int spaceBeforePoolIndex = config.indexOf(' ', poolIndex); - int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex); + if (poolIndex != -1) { + assignmentPool = poolRegex.cap(1); - assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex); + // remove the pool from the config string, the assigned node doesn't need it + config.remove(poolIndex, poolRegex.matchedLength()); } + qDebug("Type %d config[%d] = %s", type, i, config.toLocal8Bit().constData()); + Assignment* configAssignment = new Assignment(Assignment::CreateCommand, type, assignmentPool); configAssignment->setPayload(config.toUtf8()); diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index a7dd5c36f8..83296991f3 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -144,6 +144,11 @@ const char* Assignment::getTypeName() const { QDebug operator<<(QDebug debug, const Assignment &assignment) { debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) << ", Type: " << assignment.getType(); + + if (!assignment.getPool().isEmpty()) { + debug << ", Pool: " << assignment.getPool(); + } + return debug.space(); } From f853e34ab19b27f1734f7985bf39fde0c3b53ed3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 15:49:05 -0800 Subject: [PATCH 17/46] fix unix complaint for no postfix for enum --- domain-server/src/DomainServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2c1cb55d2e..715e750391 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -199,11 +199,11 @@ void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::T void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet& excludedTypes) { // enumerate over all assignment types and see if we've already excluded it - for (Assignment::Type defaultedType = Assignment::AudioMixerType; defaultedType != Assignment::AllTypes; defaultedType++) { - if (!excludedTypes.contains(defaultedType)) { + for (int defaultedType = Assignment::AudioMixerType; defaultedType != Assignment::AllTypes; defaultedType++) { + if (!excludedTypes.contains((Assignment::Type) defaultedType)) { // type has not been set from a command line or config file config, use the default // by clearing whatever exists and writing a single default assignment with no payload - Assignment* newAssignment = new Assignment(Assignment::CreateCommand, defaultedType); + Assignment* newAssignment = new Assignment(Assignment::CreateCommand, (Assignment::Type) defaultedType); addStaticAssignmentToAssignmentHash(newAssignment); } } From 703b654728734b0d58dcf69d08a79b6a22d06e11 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 17:39:37 -0800 Subject: [PATCH 18/46] make sure UUID key changes in static assignment hash, closes #1770 --- domain-server/src/DomainServer.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 715e750391..37626e8a43 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -534,13 +534,22 @@ void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment->resetUUID(); qDebug() << "Reset UUID for assignment -" << *assignment.data() << "- and added to queue. Old UUID was" - << uuidStringWithoutCurlyBraces( oldUUID); + << uuidStringWithoutCurlyBraces(oldUUID); + + // add the static assignment back under the right UUID, and to the queue + _staticAssignmentHash.insert(assignment->getUUID(), assignment); + _assignmentQueue.enqueue(assignment); + + // remove the old assignment from the _staticAssignmentHash + // this must be done last so copies are created before the assignment passed by reference is killed + _staticAssignmentHash.remove(oldUUID); } void DomainServer::nodeKilled(SharedNodePointer node) { // if this node's UUID matches a static assignment we need to throw it back in the assignment queue SharedAssignmentPointer matchedAssignment = _staticAssignmentHash.value(node->getUUID()); + if (matchedAssignment) { refreshStaticAssignmentAndAddToQueue(matchedAssignment); } @@ -633,8 +642,9 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { // if the domain-server has just restarted, // check if there are static assignments that we need to throw into the assignment queue - QHash::iterator staticAssignment = _staticAssignmentHash.begin(); - while (staticAssignment != _staticAssignmentHash.end()) { + QHash staticHashCopy = _staticAssignmentHash; + QHash::iterator staticAssignment = staticHashCopy.begin(); + while (staticAssignment != staticHashCopy.end()) { // add any of the un-matched static assignments to the queue bool foundMatchingAssignment = false; From dc70c7473338c44cd40c563f22c7a90d2f7dd3fb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 09:30:26 -0800 Subject: [PATCH 19/46] fix a double push in added particle response --- libraries/particles/src/ParticleTree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index a7472d98d1..51150722d0 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -190,7 +190,6 @@ void ParticleTree::handleAddParticleResponse(const QByteArray& packet) { int numBytesPacketHeader = numBytesForPacketHeader(packet); const unsigned char* dataAt = reinterpret_cast(packet.data()) + numBytesPacketHeader; - dataAt += numBytesPacketHeader; uint32_t creatorTokenID; memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID)); From c989a64e90d0ade8e2a5d2e3cf0e22a438ea0255 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 09:54:52 -0800 Subject: [PATCH 20/46] repair ping packet parsing in creation of reply --- libraries/shared/src/NodeList.cpp | 13 +++++++++---- libraries/shared/src/PacketHeaders.cpp | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index c5ad709fa4..8776337f6b 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -119,13 +119,15 @@ void NodeList::timePingReply(const QByteArray& packet) { if (matchingNode) { QDataStream packetStream(packet); - packetStream.device()->seek(numBytesForPacketHeader(packet)); + packetStream.skipRawData(numBytesForPacketHeader(packet)); - qint64 ourOriginalTime, othersReplyTime; + quint64 ourOriginalTime, othersReplyTime; packetStream >> ourOriginalTime >> othersReplyTime; - qint64 now = usecTimestampNow(); + qDebug() << "OT:" << ourOriginalTime << "OR:" << othersReplyTime; + + quint64 now = usecTimestampNow(); int pingTime = now - ourOriginalTime; int oneWayFlightTime = pingTime / 2; // half of the ping is our one way flight @@ -554,8 +556,11 @@ QByteArray NodeList::constructPingPacket() { } QByteArray NodeList::constructPingReplyPacket(const QByteArray& pingPacket) { + QDataStream pingPacketStream(pingPacket); + pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket)); + quint64 timeFromOriginalPing; - memcpy(&timeFromOriginalPing, pingPacket.data() + numBytesForPacketHeader(pingPacket), sizeof(timeFromOriginalPing)); + pingPacketStream >> timeFromOriginalPing; QByteArray replyPacket = byteArrayWithPopluatedHeader(PacketTypePingReply); QDataStream packetStream(&replyPacket, QIODevice::Append); diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 5d2dd52a2f..3fd51949f9 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -80,7 +80,7 @@ bool packetVersionMatch(const QByteArray& packet) { // currently this just checks if the version in the packet matches our return from versionForPacketType // may need to be expanded in the future for types and versions that take > than 1 byte - if (packet[1] == versionForPacketType(packetTypeForPacket(packet)) || packet[0] == PacketTypeStunResponse) { + if (packet[1] == versionForPacketType(packetTypeForPacket(packet)) || packetTypeForPacket(packet) == PacketTypeStunResponse) { return true; } else { PacketType mismatchType = packetTypeForPacket(packet); From ddbcfbd02f7719233e221fa078ac5bb4979aed4f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 09:56:18 -0800 Subject: [PATCH 21/46] remove an extra debug for ping packets --- libraries/shared/src/NodeList.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 8776337f6b..c0c05196dc 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -125,8 +125,6 @@ void NodeList::timePingReply(const QByteArray& packet) { packetStream >> ourOriginalTime >> othersReplyTime; - qDebug() << "OT:" << ourOriginalTime << "OR:" << othersReplyTime; - quint64 now = usecTimestampNow(); int pingTime = now - ourOriginalTime; int oneWayFlightTime = pingTime / 2; // half of the ping is our one way flight From a5b0675f2479674bcef4b502b0bb5ce49d808539 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 09:58:29 -0800 Subject: [PATCH 22/46] sendPingPackets method need not be static --- interface/src/Application.cpp | 8 ++++---- interface/src/Application.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b30fc37591..16475fcbb0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1413,10 +1413,10 @@ void Application::wheelEvent(QWheelEvent* event) { void Application::sendPingPackets() { QByteArray pingPacket = NodeList::getInstance()->constructPingPacket(); - getInstance()->controlledBroadcastToNodes(pingPacket, NodeSet() << NodeType::VoxelServer - << NodeType::ParticleServer - << NodeType::AudioMixer << NodeType::AvatarMixer - << NodeType::MetavoxelServer); + controlledBroadcastToNodes(pingPacket, NodeSet() << NodeType::VoxelServer + << NodeType::ParticleServer + << NodeType::AudioMixer << NodeType::AvatarMixer + << NodeType::MetavoxelServer); } // Every second, check the frame rates and other stuff diff --git a/interface/src/Application.h b/interface/src/Application.h index a0b52365cf..d43b624e59 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -264,7 +264,7 @@ private: void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true); static bool sendVoxelsOperation(OctreeElement* node, void* extraData); - static void sendPingPackets(); + void sendPingPackets(); void initDisplay(); void init(); From a07511ed2ca2fe5b520d911b9723c0962f4f2703 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 10:05:46 -0800 Subject: [PATCH 23/46] remove an unecessary line --- libraries/shared/src/NodeList.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index c0c05196dc..cd9356ab15 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -624,8 +624,7 @@ SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, } } -unsigned NodeList::broadcastToNodes(const QByteArray& packet, - const NodeSet& destinationNodeTypes) { +unsigned NodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) { unsigned n = 0; foreach (const SharedNodePointer& node, getNodeHash()) { From 59a528f096f8748823966140abe9829fd8e91c55 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 10:06:26 -0800 Subject: [PATCH 24/46] remove another unneeded line --- libraries/octree/src/JurisdictionListener.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index fc8ea008d1..d2c24021ac 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -45,8 +45,7 @@ bool JurisdictionListener::queueJurisdictionRequest() { NodeList* nodeList = NodeList::getInstance(); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { - if (nodeList->getNodeActiveSocketOrPing(node.data()) && - node->getType() == getNodeType()) { + if (nodeList->getNodeActiveSocketOrPing(node.data()) && node->getType() == getNodeType()) { const HifiSockAddr* nodeAddress = node->getActiveSocket(); _packetSender.queuePacketForSending(*nodeAddress, QByteArray(reinterpret_cast(bufferOut), sizeOut)); nodeCount++; From 79c8f91c78cc9f332c8caffd207520e820530a40 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 10:15:17 -0800 Subject: [PATCH 25/46] instantiate isAvatar in ScriptEngine to false, closes #1779 --- libraries/script-engine/src/ScriptEngine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 71e450d4ad..303f53aaa1 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -41,6 +41,7 @@ static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* eng ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, const QString& fileNameString, AbstractMenuInterface* menu, AbstractControllerScriptingInterface* controllerScriptingInterface) : + _isAvatar(false), _dataServerScriptingInterface(), _avatarData(NULL) { From 29abd2500fac41e311adc254beb51bd5ccbfe925 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 10:34:11 -0800 Subject: [PATCH 26/46] revert to old parsing of AvatarData --- libraries/avatars/src/AvatarData.cpp | 117 +++++++++++++-------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a8906f9167..c337f2ab95 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -172,105 +172,102 @@ int AvatarData::parseData(const QByteArray& packet) { _handData = new HandData(this); } - QDataStream packetStream(packet); - packetStream.skipRawData(numBytesForPacketHeader(packet)); + // increment to push past the packet header + const unsigned char* sourceBuffer = reinterpret_cast(packet.data()); + const unsigned char* startPosition = sourceBuffer + numBytesForPacketHeader(packet); - packetStream.readRawData(reinterpret_cast(&_position), sizeof(_position)); + // Body world position + memcpy(&_position, sourceBuffer, sizeof(float) * 3); + sourceBuffer += sizeof(float) * 3; // Body rotation (NOTE: This needs to become a quaternion to save two bytes) - uint16_t twoByteHolder; - packetStream >> twoByteHolder; - unpackFloatAngleFromTwoByte(&twoByteHolder, &_bodyYaw); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyYaw); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyPitch); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyRoll); - packetStream >> twoByteHolder; - unpackFloatAngleFromTwoByte(&twoByteHolder, &_bodyPitch); + // Body scale + sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _targetScale); - packetStream >> twoByteHolder; - unpackFloatAngleFromTwoByte(&twoByteHolder, &_bodyRoll); - - // body scale - packetStream >> twoByteHolder; - unpackFloatRatioFromTwoByte(reinterpret_cast(&twoByteHolder), _targetScale); - // Head rotation (NOTE: This needs to become a quaternion to save two bytes) float headYaw, headPitch, headRoll; - - packetStream >> twoByteHolder; - unpackFloatAngleFromTwoByte(&twoByteHolder, &headYaw); - - packetStream >> twoByteHolder; - unpackFloatAngleFromTwoByte(&twoByteHolder, &headPitch); - - packetStream >> twoByteHolder; - unpackFloatAngleFromTwoByte(&twoByteHolder, &headRoll); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll); _headData->setYaw(headYaw); _headData->setPitch(headPitch); _headData->setRoll(headRoll); - + // Head position relative to pelvis - packetStream >> _headData->_leanSideways; - packetStream >> _headData->_leanForward; - + memcpy(&_headData->_leanSideways, sourceBuffer, sizeof(_headData->_leanSideways)); + sourceBuffer += sizeof(float); + memcpy(&_headData->_leanForward, sourceBuffer, sizeof(_headData->_leanForward)); + sourceBuffer += sizeof(_headData->_leanForward); + // Hand Position - is relative to body position glm::vec3 handPositionRelative; - packetStream.readRawData(reinterpret_cast(&handPositionRelative), sizeof(handPositionRelative)); + memcpy(&handPositionRelative, sourceBuffer, sizeof(float) * 3); _handPosition = _position + handPositionRelative; + sourceBuffer += sizeof(float) * 3; + + // Lookat Position + memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); + sourceBuffer += sizeof(_headData->_lookAtPosition); - packetStream.readRawData(reinterpret_cast(&_headData->_lookAtPosition), sizeof(_headData->_lookAtPosition)); - // Instantaneous audio loudness (used to drive facial animation) //sourceBuffer += unpackFloatFromByte(sourceBuffer, _audioLoudness, MAX_AUDIO_LOUDNESS); - packetStream >> _headData->_audioLoudness; - - // the rest is a chat message + memcpy(&_headData->_audioLoudness, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + + // the rest is a chat message + int chatMessageSize = *sourceBuffer++; + _chatMessage = string((char*)sourceBuffer, chatMessageSize); + sourceBuffer += chatMessageSize * sizeof(char); - quint8 chatMessageSize; - packetStream >> chatMessageSize; - _chatMessage = string(packet.data() + packetStream.device()->pos(), chatMessageSize); - packetStream.skipRawData(chatMessageSize); - // voxel sending features... unsigned char bitItems = 0; - packetStream >> bitItems; + bitItems = (unsigned char)*sourceBuffer++; // key state, stored as a semi-nibble in the bitItems _keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT); - + // hand state, stored as a semi-nibble in the bitItems _handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT); - + _headData->_isFaceshiftConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED); - + _isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); - + // If it is connected, pack up the data if (_headData->_isFaceshiftConnected) { - packetStream >> _headData->_leftEyeBlink; - packetStream >> _headData->_rightEyeBlink; - packetStream >> _headData->_averageLoudness; - packetStream >> _headData->_browAudioLift; + memcpy(&_headData->_leftEyeBlink, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); - quint8 numBlendshapeCoefficients; - packetStream >> numBlendshapeCoefficients; + memcpy(&_headData->_rightEyeBlink, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); - _headData->_blendshapeCoefficients.resize(numBlendshapeCoefficients); - packetStream.readRawData(reinterpret_cast(_headData->_blendshapeCoefficients.data()), - numBlendshapeCoefficients * sizeof(float)); + memcpy(&_headData->_averageLoudness, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + + memcpy(&_headData->_browAudioLift, sourceBuffer, sizeof(float)); + sourceBuffer += sizeof(float); + + _headData->_blendshapeCoefficients.resize(*sourceBuffer++); + memcpy(_headData->_blendshapeCoefficients.data(), sourceBuffer, + _headData->_blendshapeCoefficients.size() * sizeof(float)); + sourceBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float); } // pupil dilation - quint8 pupilByte; - packetStream >> pupilByte; - unpackFloatFromByte(&pupilByte, _headData->_pupilDilation, 1.0f); + sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f); // leap hand data - if (packetStream.device()->pos() < packet.size()) { + if (sourceBuffer - startPosition < packet.size()) { // check passed, bytes match - packetStream.skipRawData(_handData->decodeRemoteData(packet.mid(packetStream.device()->pos()))); + sourceBuffer += _handData->decodeRemoteData(packet.mid(sourceBuffer - startPosition)); } - - return packetStream.device()->pos(); + + return sourceBuffer - startPosition; } void AvatarData::setClampedTargetScale(float targetScale) { From c70633e5d14d8368ece8f9188977a4dd70712c6a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 10:40:10 -0800 Subject: [PATCH 27/46] don't render any audio stats if no _audioOutput, closes #1783 --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index e42947bf8c..9fede84a93 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -539,7 +539,7 @@ void Audio::toggleMute() { } void Audio::render(int screenWidth, int screenHeight) { - if (_audioInput) { + if (_audioInput && _audioOutput) { glLineWidth(2.0); glBegin(GL_LINES); glColor3f(.93f, .93f, .93f); From 217135a8d6b628067858f9d48d19dc5a867bd2dc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 11:00:44 -0800 Subject: [PATCH 28/46] repairs to VoxelImporter to remove QCoreApplication warning --- interface/src/Application.cpp | 14 ++++++++------ interface/src/Application.h | 2 +- interface/src/ImportDialog.cpp | 4 ---- interface/src/VoxelImporter.cpp | 18 +++++++++--------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 66f9f8e5b7..070a20ee65 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -117,11 +117,10 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _frameCount(0), _fps(120.0f), _justStarted(true), - _voxelImporter(_window), + _voxelImporter(NULL), _wantToKillLocalVoxels(false), _audioScope(256, 200, true), - _avatarManager(), - _myAvatar(NULL), + _myAvatar(), _profile(QString()), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), _mouseX(0), @@ -1673,7 +1672,12 @@ void Application::exportVoxels() { } void Application::importVoxels() { - if (_voxelImporter.exec()) { + if (!_voxelImporter) { + _voxelImporter = new VoxelImporter(_window); + _voxelImporter->init(_settings); + } + + if (_voxelImporter->exec()) { qDebug("[DEBUG] Import succeeded."); } else { qDebug("[DEBUG] Import failed."); @@ -1813,8 +1817,6 @@ void Application::init() { _sharedVoxelSystem.changeTree(&_clipboard); delete tmpTree; - _voxelImporter.init(_settings); - _environment.init(); _glowEffect.init(); diff --git a/interface/src/Application.h b/interface/src/Application.h index d43b624e59..c83437949c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -355,7 +355,7 @@ private: VoxelSystem _voxels; VoxelTree _clipboard; // if I copy/paste - VoxelImporter _voxelImporter; + VoxelImporter* _voxelImporter; VoxelSystem _sharedVoxelSystem; ViewFrustum _sharedVoxelSystemViewFrustum; diff --git a/interface/src/ImportDialog.cpp b/interface/src/ImportDialog.cpp index 28e39f1abd..ac7853629c 100644 --- a/interface/src/ImportDialog.cpp +++ b/interface/src/ImportDialog.cpp @@ -231,10 +231,6 @@ void ImportDialog::setLayout() { widget = findChild("treeView"); widget->setAttribute(Qt::WA_MacShowFocusRect, false); - // remove reference to treeView - widget = NULL; - widget->deleteLater(); - switchToResourcesParentIfRequired(); QFile styleSheet("resources/styles/import_dialog.qss"); if (styleSheet.open(QIODevice::ReadOnly)) { diff --git a/interface/src/VoxelImporter.cpp b/interface/src/VoxelImporter.cpp index 0011b0abb7..653d04cee4 100644 --- a/interface/src/VoxelImporter.cpp +++ b/interface/src/VoxelImporter.cpp @@ -24,15 +24,15 @@ private: const QString SETTINGS_GROUP_NAME = "VoxelImport"; const QString IMPORT_DIALOG_SETTINGS_KEY = "ImportDialogSettings"; -VoxelImporter::VoxelImporter(QWidget* parent) - : QObject(parent), - _voxelTree(true), - _importDialog(parent), - _currentTask(NULL), - _nextTask(NULL) { - - connect(&_importDialog, SIGNAL(currentChanged(QString)), SLOT(preImport())); - connect(&_importDialog, SIGNAL(accepted()), SLOT(import())); +VoxelImporter::VoxelImporter(QWidget* parent) : + QObject(parent), + _voxelTree(true), + _importDialog(parent), + _currentTask(NULL), + _nextTask(NULL) +{ + connect(&_importDialog, &QFileDialog::currentChanged, this, &VoxelImporter::preImport); + connect(&_importDialog, &QFileDialog::accepted, this, &VoxelImporter::import); } void VoxelImporter::saveSettings(QSettings* settings) { From 4ed748752f736293f8d5a994e2f6d18f40f5c2dc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 11:20:36 -0800 Subject: [PATCH 29/46] fix incorrect packet position in AvatarData, closes #1786 --- libraries/avatars/src/AvatarData.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index c337f2ab95..98afa76107 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -173,8 +173,8 @@ int AvatarData::parseData(const QByteArray& packet) { } // increment to push past the packet header - const unsigned char* sourceBuffer = reinterpret_cast(packet.data()); - const unsigned char* startPosition = sourceBuffer + numBytesForPacketHeader(packet); + const unsigned char* startPosition = reinterpret_cast(packet.data()); + const unsigned char* sourceBuffer = startPosition + numBytesForPacketHeader(packet); // Body world position memcpy(&_position, sourceBuffer, sizeof(float) * 3); From 4bf8f3a465ed369df0d5e2f8b0c34d1c91165d6f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 11:29:15 -0800 Subject: [PATCH 30/46] reinstate old HandData parsing --- libraries/avatars/src/HandData.cpp | 43 +++++++++--------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index d947b894aa..2e24c48cfa 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -162,29 +162,21 @@ int HandData::encodeRemoteData(unsigned char* destinationBuffer) { int HandData::decodeRemoteData(const QByteArray& dataByteArray) { QDataStream packetStream(dataByteArray); - quint8 numHands; - packetStream >> numHands; + const unsigned char* startPosition; + const unsigned char* sourceBuffer = startPosition = reinterpret_cast(dataByteArray.data()); + unsigned int numHands = *sourceBuffer++; for (unsigned int handIndex = 0; handIndex < numHands; ++handIndex) { if (handIndex >= getNumPalms()) addNewPalm(); PalmData& palm = getPalms()[handIndex]; - + glm::vec3 handPosition; glm::vec3 handNormal; - qint16 twoByteHolder; + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, handPosition, fingerVectorRadix); + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, handNormal, fingerVectorRadix); + unsigned int numFingers = *sourceBuffer++; - packetStream >> twoByteHolder; - unpackFloatVec3FromSignedTwoByteFixed(reinterpret_cast(&twoByteHolder), - handPosition, fingerVectorRadix); - - packetStream >> twoByteHolder; - unpackFloatVec3FromSignedTwoByteFixed(reinterpret_cast(&twoByteHolder), - handNormal, fingerVectorRadix); - - quint8 numFingers; - packetStream >> numFingers; - palm.setRawPosition(handPosition); palm.setRawNormal(handNormal); palm.setActive(true); @@ -195,18 +187,12 @@ int HandData::decodeRemoteData(const QByteArray& dataByteArray) { for (unsigned int fingerIndex = 0; fingerIndex < numFingers; ++fingerIndex) { if (fingerIndex < palm.getNumFingers()) { FingerData& finger = palm.getFingers()[fingerIndex]; - + glm::vec3 tipPosition; glm::vec3 rootPosition; + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, tipPosition, fingerVectorRadix); + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, rootPosition, fingerVectorRadix); - packetStream >> twoByteHolder; - unpackFloatVec3FromSignedTwoByteFixed(reinterpret_cast(&twoByteHolder), tipPosition, - fingerVectorRadix); - - packetStream >> twoByteHolder; - unpackFloatVec3FromSignedTwoByteFixed(reinterpret_cast(&twoByteHolder), rootPosition, - fingerVectorRadix); - finger.setRawTipPosition(tipPosition); finger.setRawRootPosition(rootPosition); finger.setActive(true); @@ -225,14 +211,9 @@ int HandData::decodeRemoteData(const QByteArray& dataByteArray) { } // One byte for error checking safety. - unsigned char requiredLength = packetStream.device()->pos(); - - unsigned char checkLength; - packetStream >> checkLength; - + unsigned char requiredLength = (unsigned char)(sourceBuffer - startPosition); + unsigned char checkLength = *sourceBuffer++; assert(checkLength == requiredLength); - - return packetStream.device()->pos(); } void HandData::setFingerTrailLength(unsigned int length) { From 9d8234799433e678fcb7034dd013db11ef75df1e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 11:32:23 -0800 Subject: [PATCH 31/46] add a missing return --- libraries/avatars/src/HandData.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 2e24c48cfa..cca8ad45cb 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -214,6 +214,8 @@ int HandData::decodeRemoteData(const QByteArray& dataByteArray) { unsigned char requiredLength = (unsigned char)(sourceBuffer - startPosition); unsigned char checkLength = *sourceBuffer++; assert(checkLength == requiredLength); + + return sourceBuffer - startPosition; } void HandData::setFingerTrailLength(unsigned int length) { From bd1d0201e085d34a23e3e88ebbce7d88217d6f7a Mon Sep 17 00:00:00 2001 From: Lucas Crisman Date: Fri, 31 Jan 2014 16:52:20 -0300 Subject: [PATCH 32/46] Updated Ubuntu package requirements --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bc32998113..afa7877c23 100644 --- a/README.md +++ b/README.md @@ -71,8 +71,16 @@ We have successfully built on OS X 10.8, Ubuntu and a few other modern Linux distributions. A Windows build is planned for the future, but not currently in development. -On a fresh Ubuntu 13.10 install, these are all the packages you need to grab and build the hifi project: -
sudo apt-get install build-essential cmake git libcurl4-openssl-dev libqt5scripttools5 libqt5svg5-dev libqt5webkit5-dev libqt5location5 qtlocation5-dev qtdeclarative5-dev qtscript5-dev qtsensors5-dev qtmultimedia5-dev qtquick1-5-dev libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev
+On a fresh Ubuntu 13.10 install, get these requirements from Ubuntu repositories: + + sudo apt-get install build-essential cmake git libcurl4-openssl-dev libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev + +Then [download lastest Qt packages](http://qt-project.org/downloads), untar/install to your prefered path +and set your `QT_CMAKE_PREFIX_PATH` environment variable as described above in the CMake section. + +It's recommended that you set the variable automatically on each shell instance to save this task in the future, such as: + + echo 'export QT_CMAKE_PREFIX_PATH=~/Qt5.2.0/5.2.0/gcc_64/lib/cmake' >> ~/.bashrc Running Interface ----- From 73aa73fd5865cae1bb07ca7d9b988ad0a02fce1a Mon Sep 17 00:00:00 2001 From: Lucas Crisman Date: Fri, 31 Jan 2014 17:00:27 -0300 Subject: [PATCH 33/46] joining paragraphs --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index afa7877c23..7679054630 100644 --- a/README.md +++ b/README.md @@ -76,9 +76,9 @@ On a fresh Ubuntu 13.10 install, get these requirements from Ubuntu repositories sudo apt-get install build-essential cmake git libcurl4-openssl-dev libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev Then [download lastest Qt packages](http://qt-project.org/downloads), untar/install to your prefered path -and set your `QT_CMAKE_PREFIX_PATH` environment variable as described above in the CMake section. - -It's recommended that you set the variable automatically on each shell instance to save this task in the future, such as: +and set your `QT_CMAKE_PREFIX_PATH` environment variable as described above in the CMake section. It's +recommended that you set the variable automatically on each shell instance to save this task in the future, +such as: echo 'export QT_CMAKE_PREFIX_PATH=~/Qt5.2.0/5.2.0/gcc_64/lib/cmake' >> ~/.bashrc From 4573eaebc679989bf916eed18f94d1a69e9a78c2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 12:02:24 -0800 Subject: [PATCH 34/46] fix multiple avatar parsing in AvatarManager --- assignment-client/src/avatars/AvatarMixer.cpp | 1 - interface/src/avatar/AvatarManager.cpp | 4 ++-- libraries/avatars/src/HandData.cpp | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 014008d35e..6dc63a6dd7 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -70,7 +70,6 @@ void broadcastAvatarData() { QByteArray avatarByteArray; avatarByteArray.append(otherNode->getUUID().toRfc4122()); - AvatarData *nodeData = (AvatarData *)otherNode->getLinkedData(); avatarByteArray.append(nodeData->toByteArray()); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 57f187603b..ba9dddde07 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -206,7 +206,7 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const int bytesRead = numBytesForPacketHeader(datagram); QByteArray dummyAvatarByteArray = byteArrayWithPopluatedHeader(PacketTypeAvatarData); - int numDummyByteArrayHeaderBytes = dummyAvatarByteArray.size(); + int numDummyByteArrayHeaderBytes = dummyAvatarByteArray.size(); // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) @@ -237,7 +237,7 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const // make this Avatar's UUID the UUID in the packet and tack the remaining data onto the end dummyAvatarByteArray.replace(numDummyByteArrayHeaderBytes - NUM_BYTES_RFC4122_UUID, - NUM_BYTES_RFC4122_UUID + datagram.size() - bytesRead, + datagram.size() - bytesRead, datagram.mid(bytesRead)); // have the matching (or new) avatar parse the data from the packet diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index cca8ad45cb..5a923eea93 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -160,8 +160,6 @@ int HandData::encodeRemoteData(unsigned char* destinationBuffer) { } int HandData::decodeRemoteData(const QByteArray& dataByteArray) { - QDataStream packetStream(dataByteArray); - const unsigned char* startPosition; const unsigned char* sourceBuffer = startPosition = reinterpret_cast(dataByteArray.data()); unsigned int numHands = *sourceBuffer++; From 18ce012d7aba237b3238c18b29b52ad0c3a9117a Mon Sep 17 00:00:00 2001 From: Lucas Crisman Date: Fri, 31 Jan 2014 17:03:57 -0300 Subject: [PATCH 35/46] simplifying text --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 7679054630..a42bbd1626 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,7 @@ On a fresh Ubuntu 13.10 install, get these requirements from Ubuntu repositories Then [download lastest Qt packages](http://qt-project.org/downloads), untar/install to your prefered path and set your `QT_CMAKE_PREFIX_PATH` environment variable as described above in the CMake section. It's -recommended that you set the variable automatically on each shell instance to save this task in the future, -such as: +recommended to set the variable automatically on each shell instance to save this task in the future: echo 'export QT_CMAKE_PREFIX_PATH=~/Qt5.2.0/5.2.0/gcc_64/lib/cmake' >> ~/.bashrc From 2cc6d2218144cb5ceac5e36c15b1c46e59ea67c5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 12:44:09 -0800 Subject: [PATCH 36/46] fix push bytesRead when creating dummy Avatar packets, closes #1794 --- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- interface/src/avatar/AvatarManager.cpp | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 6dc63a6dd7..358e507fc4 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -70,7 +70,7 @@ void broadcastAvatarData() { QByteArray avatarByteArray; avatarByteArray.append(otherNode->getUUID().toRfc4122()); - AvatarData *nodeData = (AvatarData *)otherNode->getLinkedData(); + AvatarData* nodeData = (AvatarData*) otherNode->getLinkedData(); avatarByteArray.append(nodeData->toByteArray()); if (avatarByteArray.size() + mixedAvatarByteArray.size() > MAX_PACKET_SIZE) { diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index ba9dddde07..24431cf3f3 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -206,7 +206,8 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const int bytesRead = numBytesForPacketHeader(datagram); QByteArray dummyAvatarByteArray = byteArrayWithPopluatedHeader(PacketTypeAvatarData); - int numDummyByteArrayHeaderBytes = dummyAvatarByteArray.size(); + int numDummyHeaderBytes = dummyAvatarByteArray.size(); + int numDummyHeaderBytesWithoutUUID = numDummyHeaderBytes - NUM_BYTES_RFC4122_UUID; // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) @@ -233,15 +234,13 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const } // copy the rest of the packet to the avatarData holder so we can read the next Avatar from there - dummyAvatarByteArray.resize(numDummyByteArrayHeaderBytes); + dummyAvatarByteArray.resize(numDummyHeaderBytesWithoutUUID); // make this Avatar's UUID the UUID in the packet and tack the remaining data onto the end - dummyAvatarByteArray.replace(numDummyByteArrayHeaderBytes - NUM_BYTES_RFC4122_UUID, - datagram.size() - bytesRead, - datagram.mid(bytesRead)); + dummyAvatarByteArray.append(datagram.mid(bytesRead)); // have the matching (or new) avatar parse the data from the packet - bytesRead += matchingAvatar->parseData(dummyAvatarByteArray); + bytesRead += matchingAvatar->parseData(dummyAvatarByteArray) - numDummyHeaderBytesWithoutUUID; } } From b16d03c42a8ed2a6a551e2aeadce3399a857587d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 12:46:03 -0800 Subject: [PATCH 37/46] remove an unneeded todo --- interface/src/avatar/AvatarManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 24431cf3f3..6a44eb98aa 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -213,7 +213,6 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const // only add them if mixerWeakPointer points to something (meaning that mixer is still around) while (bytesRead < datagram.size() && mixerWeakPointer.data()) { QUuid nodeUUID = QUuid::fromRfc4122(datagram.mid(bytesRead, NUM_BYTES_RFC4122_UUID)); - // TODO: skip the data if nodeUUID is same as MY_AVATAR_KEY AvatarSharedPointer matchingAvatar = _avatarHash.value(nodeUUID); From 5caaf0dc7f1710b97c0bce05abd80fb9ff2746cd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 31 Jan 2014 13:28:56 -0800 Subject: [PATCH 38/46] check against NULL node from nodeWithUUID() --- libraries/octree/src/JurisdictionSender.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp index 52990397db..854496e40f 100644 --- a/libraries/octree/src/JurisdictionSender.cpp +++ b/libraries/octree/src/JurisdictionSender.cpp @@ -64,7 +64,7 @@ bool JurisdictionSender::process() { _nodesRequestingJurisdictions.pop(); SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(nodeUUID); - if (node->getActiveSocket() != NULL) { + if (node && node->getActiveSocket() != NULL) { const HifiSockAddr* nodeAddress = node->getActiveSocket(); _packetSender.queuePacketForSending(*nodeAddress, QByteArray(reinterpret_cast(bufferOut), sizeOut)); nodeCount++; From 254a0c0aed17c62b24cc51b1ac036a8ff6533d59 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 13:44:24 -0800 Subject: [PATCH 39/46] remove a double push on UUID in OctreeQuery --- libraries/octree/src/OctreeQuery.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 51b73a9ed2..ed8bfd0da4 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -103,9 +103,6 @@ int OctreeQuery::parseData(const QByteArray& packet) { const unsigned char* startPosition = reinterpret_cast(packet.data()); const unsigned char* sourceBuffer = startPosition + numBytesPacketHeader; - // push past the node session UUID - sourceBuffer += NUM_BYTES_RFC4122_UUID; - // user UUID _uuid = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID)); sourceBuffer += NUM_BYTES_RFC4122_UUID; From 9b549723d3e302b9fbb928309af4836e496dc31e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 13:47:59 -0800 Subject: [PATCH 40/46] remove unused UUID from OctreeQuery --- libraries/octree/src/OctreeQuery.cpp | 10 ---------- libraries/octree/src/OctreeQuery.h | 5 ----- 2 files changed, 15 deletions(-) diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index ed8bfd0da4..5c67715ab9 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -24,7 +24,6 @@ static const float fingerVectorRadix = 4; // bits of precision when converting f OctreeQuery::OctreeQuery() : NodeData(), - _uuid(), _cameraPosition(0,0,0), _cameraOrientation(), _cameraFov(0.0f), @@ -53,11 +52,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // that can pack any type given the number of bytes // and return the number of bytes to push the pointer - // UUID - QByteArray uuidByteArray = _uuid.toRfc4122(); - memcpy(destinationBuffer, uuidByteArray.constData(), uuidByteArray.size()); - destinationBuffer += uuidByteArray.size(); - // camera details memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); destinationBuffer += sizeof(_cameraPosition); @@ -103,10 +97,6 @@ int OctreeQuery::parseData(const QByteArray& packet) { const unsigned char* startPosition = reinterpret_cast(packet.data()); const unsigned char* sourceBuffer = startPosition + numBytesPacketHeader; - // user UUID - _uuid = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID)); - sourceBuffer += NUM_BYTES_RFC4122_UUID; - // camera details memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); sourceBuffer += sizeof(_cameraPosition); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index acb4b7cb32..800d30b7cd 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -57,9 +57,6 @@ public: int getBroadcastData(unsigned char* destinationBuffer); int parseData(const QByteArray& packet); - QUuid& getUUID() { return _uuid; } - void setUUID(const QUuid& uuid) { _uuid = uuid; } - // getters for camera details const glm::vec3& getCameraPosition() const { return _cameraPosition; } const glm::quat& getCameraOrientation() const { return _cameraOrientation; } @@ -101,8 +98,6 @@ public slots: void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } protected: - QUuid _uuid; - // camera details for the avatar glm::vec3 _cameraPosition; glm::quat _cameraOrientation; From 4b18e37dfb100020df4ff77939282074d1fc1bd4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 14:13:05 -0800 Subject: [PATCH 41/46] fix for ttf return in DS, closes #1769 --- libraries/embedded-webserver/src/HTTPManager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index 849bf593cd..a217555a78 100755 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -63,7 +63,7 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QString& p QFile localFile(filePath); localFile.open(QIODevice::ReadOnly); - QString localFileString(localFile.readAll()); + QByteArray localFileData = localFile.readAll(); QFileInfo localFileInfo(filePath); @@ -77,6 +77,7 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QString& p int matchPosition = 0; + QString localFileString(localFileData); while ((matchPosition = includeRegExp.indexIn(localFileString, matchPosition)) != -1) { // check if this is a file or vitual include @@ -105,9 +106,11 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QString& p // push the match position forward so we can check the next match matchPosition += includeRegExp.matchedLength(); } + + localFileData = localFileString.toLocal8Bit(); } - connection->respond(HTTPConnection::StatusCode200, localFileString.toLocal8Bit(), + connection->respond(HTTPConnection::StatusCode200, localFileData, qPrintable(mimeDatabase.mimeTypeForFile(filePath).name())); } else { From dd83ff05380277fb3398984f7d00fa0c1a2b5ce4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 14:36:50 -0800 Subject: [PATCH 42/46] move isAvatar property access to Agent object --- assignment-client/src/Agent.cpp | 3 +++ assignment-client/src/Agent.h | 5 +++++ libraries/script-engine/src/ScriptEngine.cpp | 2 +- libraries/script-engine/src/ScriptEngine.h | 2 -- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 84714259e5..2694bf83e2 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -101,6 +101,9 @@ void Agent::run() { // give this AvatarData object to the script engine _scriptEngine.setAvatarData(&scriptedAvatar, "Avatar"); + + // register ourselves to the script engine + _scriptEngine.registerGlobalObject("Agent", this); _scriptEngine.setScriptContents(scriptContents); _scriptEngine.run(); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 146cb71df4..8b2038a8b0 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -21,9 +21,14 @@ class Agent : public ThreadedAssignment { Q_OBJECT + + Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar) public: Agent(const QByteArray& packet); + void setIsAvatar(bool isAvatar) { _scriptEngine.setIsAvatar(isAvatar); } + bool isAvatar() const { return _scriptEngine.isAvatar(); } + public slots: void run(); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 6ea3742592..9a7a9197b0 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -133,7 +133,7 @@ void ScriptEngine::init() { QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject(); _engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); - registerGlobalObject("Agent", this); + registerGlobalObject("Script", this); registerGlobalObject("Audio", &_audioScriptingInterface); registerGlobalObject("Controller", _controllerScriptingInterface); registerGlobalObject("Data", &_dataServerScriptingInterface); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index c2188cca63..8f29379266 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -31,8 +31,6 @@ const QString NO_SCRIPT(""); class ScriptEngine : public QObject { Q_OBJECT - - Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar) public: ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false, const QString& scriptMenuName = QString(""), AbstractMenuInterface* menu = NULL, From 9015b24aa5ec5af9da0508aa5c831c6e3a4399a2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 14:41:24 -0800 Subject: [PATCH 43/46] update the script examples for new nomenclature --- examples/clap.js | 2 +- examples/collidingParticles.js | 6 +++--- examples/controllerExample.js | 4 ++-- examples/count.js | 4 ++-- examples/drumStick.js | 2 +- examples/editParticleExample.js | 8 ++++---- examples/findParticleExample.js | 8 ++++---- examples/fountain.js | 4 ++-- examples/gameoflife.js | 2 +- examples/gun.js | 2 +- examples/lookWithMouse.js | 4 ++-- examples/movingVoxel.js | 2 +- examples/paintGun.js | 2 +- examples/particleBird.js | 4 ++-- examples/particleModelExample.js | 6 +++--- examples/playSound.js | 2 +- examples/rideAlongWithAParticleExample.js | 4 ++-- examples/toyball.js | 2 +- examples/voxelBird.js | 2 +- 19 files changed, 35 insertions(+), 35 deletions(-) diff --git a/examples/clap.js b/examples/clap.js index fdd2b29aa2..81ccda64b7 100644 --- a/examples/clap.js +++ b/examples/clap.js @@ -62,4 +62,4 @@ function maybePlaySound() { } // Connect a call back that happens every frame -Agent.willSendVisualDataCallback.connect(maybePlaySound); \ No newline at end of file +Script.willSendVisualDataCallback.connect(maybePlaySound); \ No newline at end of file diff --git a/examples/collidingParticles.js b/examples/collidingParticles.js index cf1fce5660..d202b31d97 100644 --- a/examples/collidingParticles.js +++ b/examples/collidingParticles.js @@ -1,4 +1,4 @@ -// +Script// // collidingParticles.js // hifi // @@ -132,7 +132,7 @@ function draw() { print(scriptB); numberParticlesAdded++; } else { - Agent.stop(); + Script.stop(); } print("Particles Stats: " + Particles.getLifetimeInSeconds() + " seconds," + @@ -150,5 +150,5 @@ function draw() { // register the call back so it fires before each data send print("here...\n"); Particles.setPacketsPerSecond(40000); -Agent.willSendVisualDataCallback.connect(draw); +Script.willSendVisualDataCallback.connect(draw); print("and here...\n"); diff --git a/examples/controllerExample.js b/examples/controllerExample.js index 95561dc9dc..43eb516cee 100644 --- a/examples/controllerExample.js +++ b/examples/controllerExample.js @@ -82,7 +82,7 @@ function touchEndEvent(event) { } // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(checkController); +Script.willSendVisualDataCallback.connect(checkController); // Map keyPress and mouse move events to our callbacks Controller.keyPressEvent.connect(keyPressEvent); @@ -199,4 +199,4 @@ function scriptEnding() { Controller.releaseTouchEvents(); } -Agent.scriptEnding.connect(scriptEnding); +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/count.js b/examples/count.js index 917bec342d..29799a8271 100644 --- a/examples/count.js +++ b/examples/count.js @@ -20,7 +20,7 @@ function scriptEnding() { } // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(displayCount); +Script.willSendVisualDataCallback.connect(displayCount); // register our scriptEnding callback -Agent.scriptEnding.connect(scriptEnding); +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/drumStick.js b/examples/drumStick.js index 955fddbdee..78de8351db 100644 --- a/examples/drumStick.js +++ b/examples/drumStick.js @@ -69,4 +69,4 @@ function checkSticks() { } // Connect a call back that happens every frame -Agent.willSendVisualDataCallback.connect(checkSticks); \ No newline at end of file +Script.willSendVisualDataCallback.connect(checkSticks); \ No newline at end of file diff --git a/examples/editParticleExample.js b/examples/editParticleExample.js index 61e32c4d55..5774eda689 100644 --- a/examples/editParticleExample.js +++ b/examples/editParticleExample.js @@ -44,7 +44,7 @@ var particleID = Particles.addParticle(originalProperties); function moveParticle() { if (count >= moveUntil) { - //Agent.stop(); + //Script.stop(); // delete it... if (count == moveUntil) { @@ -54,8 +54,8 @@ function moveParticle() { // stop it... if (count >= stopAfter) { - print("calling Agent.stop()"); - Agent.stop(); + print("calling Script.stop()"); + Script.stop(); } count++; @@ -86,5 +86,5 @@ function moveParticle() { // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(moveParticle); +Script.willSendVisualDataCallback.connect(moveParticle); diff --git a/examples/findParticleExample.js b/examples/findParticleExample.js index bd20e6ded7..5eb257d502 100644 --- a/examples/findParticleExample.js +++ b/examples/findParticleExample.js @@ -65,8 +65,8 @@ function findParticles() { // run for a while, then clean up // stop it... if (iteration >= 100) { - print("calling Agent.stop()"); - Agent.stop(); + print("calling Script.stop()"); + Script.stop(); } print("--------------------------"); @@ -122,7 +122,7 @@ function findParticles() { // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(findParticles); +Script.willSendVisualDataCallback.connect(findParticles); // register our scriptEnding callback -Agent.scriptEnding.connect(scriptEnding); +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/fountain.js b/examples/fountain.js index a095f91ed3..3c943d72a0 100644 --- a/examples/fountain.js +++ b/examples/fountain.js @@ -60,8 +60,8 @@ function makeFountain() { totalParticles++; } if (totalParticles > 100) { - Agent.stop(); + Script.stop(); } } // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(makeFountain); \ No newline at end of file +Script.willSendVisualDataCallback.connect(makeFountain); \ No newline at end of file diff --git a/examples/gameoflife.js b/examples/gameoflife.js index 09fae07204..6779941dc7 100644 --- a/examples/gameoflife.js +++ b/examples/gameoflife.js @@ -128,6 +128,6 @@ print("step()..."); } print("here"); -Agent.willSendVisualDataCallback.connect(step); +Script.willSendVisualDataCallback.connect(step); Voxels.setPacketsPerSecond(200); print("now here"); diff --git a/examples/gun.js b/examples/gun.js index 3f8eefe3e2..e7cd2973e2 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -99,4 +99,4 @@ function checkController() { // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(checkController); +Script.willSendVisualDataCallback.connect(checkController); diff --git a/examples/lookWithMouse.js b/examples/lookWithMouse.js index 79fad76a1b..f404019bc1 100644 --- a/examples/lookWithMouse.js +++ b/examples/lookWithMouse.js @@ -70,5 +70,5 @@ MyAvatar.bodyPitch = 0; MyAvatar.bodyRoll = 0; // would be nice to change to update -Agent.willSendVisualDataCallback.connect(update); -Agent.scriptEnding.connect(scriptEnding); +Script.willSendVisualDataCallback.connect(update); +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/movingVoxel.js b/examples/movingVoxel.js index 0aadf7b30c..14a7e671c6 100644 --- a/examples/movingVoxel.js +++ b/examples/movingVoxel.js @@ -41,4 +41,4 @@ function moveVoxel() { Voxels.setPacketsPerSecond(300); // Connect a call back that happens every frame -Agent.willSendVisualDataCallback.connect(moveVoxel); \ No newline at end of file +Script.willSendVisualDataCallback.connect(moveVoxel); \ No newline at end of file diff --git a/examples/paintGun.js b/examples/paintGun.js index b78e6abb0b..56e916a183 100644 --- a/examples/paintGun.js +++ b/examples/paintGun.js @@ -93,4 +93,4 @@ function checkController() { // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(checkController); +Script.willSendVisualDataCallback.connect(checkController); diff --git a/examples/particleBird.js b/examples/particleBird.js index 6a4cf79a40..c1c26058e6 100644 --- a/examples/particleBird.js +++ b/examples/particleBird.js @@ -95,7 +95,7 @@ function moveBird() { var nowTimeInSeconds = new Date().getTime() / 1000; if ((nowTimeInSeconds - startTimeInSeconds) >= birdLifetime) { print("our bird is dying, stop our script"); - Agent.stop(); + Script.stop(); return; } @@ -171,4 +171,4 @@ function moveBird() { } } // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(moveBird); +Script.willSendVisualDataCallback.connect(moveBird); diff --git a/examples/particleModelExample.js b/examples/particleModelExample.js index 9f19069ee9..e95cc0c2bf 100644 --- a/examples/particleModelExample.js +++ b/examples/particleModelExample.js @@ -37,8 +37,8 @@ var ballParticleID = Particles.addParticle(ballProperties); function endAfterAWhile() { // stop it... if (count >= stopAfter) { - print("calling Agent.stop()"); - Agent.stop(); + print("calling Script.stop()"); + Script.stop(); } print("count =" + count); @@ -47,5 +47,5 @@ function endAfterAWhile() { // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(endAfterAWhile); +Script.willSendVisualDataCallback.connect(endAfterAWhile); diff --git a/examples/playSound.js b/examples/playSound.js index 6631d5526a..657f052aa5 100644 --- a/examples/playSound.js +++ b/examples/playSound.js @@ -17,4 +17,4 @@ function maybePlaySound() { } // Connect a call back that happens every frame -Agent.willSendVisualDataCallback.connect(maybePlaySound); \ No newline at end of file +Script.willSendVisualDataCallback.connect(maybePlaySound); \ No newline at end of file diff --git a/examples/rideAlongWithAParticleExample.js b/examples/rideAlongWithAParticleExample.js index eca9fe7f4c..b2b6627063 100644 --- a/examples/rideAlongWithAParticleExample.js +++ b/examples/rideAlongWithAParticleExample.js @@ -37,7 +37,7 @@ function rideWithParticle() { y: propertiesA.position.y + 2, z: propertiesA.position.z }; } else { - Agent.stop(); + Script.stop(); } iteration++; @@ -46,5 +46,5 @@ function rideWithParticle() { // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(rideWithParticle); +Script.willSendVisualDataCallback.connect(rideWithParticle); diff --git a/examples/toyball.js b/examples/toyball.js index 6c40fc2932..c5672877f7 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -226,4 +226,4 @@ function checkController() { // register the call back so it fires before each data send -Agent.willSendVisualDataCallback.connect(checkController); +Script.willSendVisualDataCallback.connect(checkController); diff --git a/examples/voxelBird.js b/examples/voxelBird.js index 54c0129045..254f93c21e 100644 --- a/examples/voxelBird.js +++ b/examples/voxelBird.js @@ -130,4 +130,4 @@ function moveBird() { Voxels.setPacketsPerSecond(10000); // Connect a call back that happens every frame -Agent.willSendVisualDataCallback.connect(moveBird); \ No newline at end of file +Script.willSendVisualDataCallback.connect(moveBird); \ No newline at end of file From 8fc55bd196fa8b70fdc4da7d4cacf4ef1fae2391 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 14:56:04 -0800 Subject: [PATCH 44/46] add user UUID to application window title --- interface/src/Application.cpp | 16 +++++----------- interface/src/avatar/Profile.cpp | 5 ++++- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4947fb008f..bf17736368 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4003,18 +4003,12 @@ void Application::setMenuShortcutsEnabled(bool enabled) { } void Application::updateWindowTitle(){ - QString title = ""; - - QString buildVersion = " (build " + applicationVersion() + ")"; - - QString username = _profile.getUsername(); - if(!username.isEmpty()){ - title += username; - title += " @ "; - } - title += NodeList::getInstance()->getDomainHostname(); - title += buildVersion; + QString buildVersion = " (build " + applicationVersion() + ")"; + NodeList* nodeList = NodeList::getInstance(); + + QString title = QString() + _profile.getUsername() + " " + nodeList->getOwnerUUID().toString() + + " @ " + nodeList->getDomainHostname() + buildVersion; qDebug("Application title set to: %s", title.toStdString().c_str()); _window->setWindowTitle(title); diff --git a/interface/src/avatar/Profile.cpp b/interface/src/avatar/Profile.cpp index 74f47bd658..902a0ea12a 100644 --- a/interface/src/avatar/Profile.cpp +++ b/interface/src/avatar/Profile.cpp @@ -53,7 +53,10 @@ void Profile::setUUID(const QUuid& uuid) { // when the UUID is changed we need set it appropriately on the NodeList instance NodeList::getInstance()->setOwnerUUID(uuid); - } + + // ask for a window title update so the new UUID is presented + Application::getInstance()->updateWindowTitle(); + } } void Profile::setFaceModelURL(const QUrl& faceModelURL) { From dba7fbceac46799b4e9495158cd6e307ead97038 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 15:00:35 -0800 Subject: [PATCH 45/46] remove extra Script and commented out line --- examples/collidingParticles.js | 2 +- examples/editParticleExample.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/collidingParticles.js b/examples/collidingParticles.js index d202b31d97..81ccfe108b 100644 --- a/examples/collidingParticles.js +++ b/examples/collidingParticles.js @@ -1,4 +1,4 @@ -Script// +// // collidingParticles.js // hifi // diff --git a/examples/editParticleExample.js b/examples/editParticleExample.js index 5774eda689..152bb18fca 100644 --- a/examples/editParticleExample.js +++ b/examples/editParticleExample.js @@ -44,7 +44,6 @@ var particleID = Particles.addParticle(originalProperties); function moveParticle() { if (count >= moveUntil) { - //Script.stop(); // delete it... if (count == moveUntil) { From c754663582609b2c3ac15eaa1f67195fb78b04cc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 17:09:08 -0800 Subject: [PATCH 46/46] force queued connection for readyRead on node socket in case it moves, closes #1685 --- assignment-client/src/AssignmentClient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index cdf0da43de..b2a5555e36 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -90,7 +90,8 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS); // connect our readPendingDatagrams method to the readyRead() signal of the socket - connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); + connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams, + Qt::QueuedConnection); } void AssignmentClient::sendAssignmentRequest() {