diff --git a/README.md b/README.md
index bc32998113..a42bbd1626 100644
--- a/README.md
+++ b/README.md
@@ -71,8 +71,15 @@ 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 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
Running Interface
-----
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/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() {
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/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp
index 014008d35e..358e507fc4 100644
--- a/assignment-client/src/avatars/AvatarMixer.cpp
+++ b/assignment-client/src/avatars/AvatarMixer.cpp
@@ -70,8 +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/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index 6e4a4cdff4..37626e8a43 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,65 +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),
- _assignmentQueueMutex(),
+ _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);
@@ -94,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 + 1);
+ }
+}
+
+// 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;
+
+ 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);
+
+ // check the config string for a pool
+ QString assignmentPool;
+
+ int poolIndex = poolRegex.indexIn(config);
+
+ if (poolIndex != -1) {
+ assignmentPool = poolRegex.cap(1);
+
+ // 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());
+
+ addStaticAssignmentToAssignmentHash(configAssignment);
+ }
+}
+
+void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet& excludedTypes) {
+ // enumerate over all assignment types and see if we've already excluded it
+ 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, (Assignment::Type) defaultedType);
+ addStaticAssignmentToAssignmentHash(newAssignment);
+ }
+ }
}
void DomainServer::readAvailableDatagrams() {
@@ -148,13 +259,13 @@ void DomainServer::readAvailableDatagrams() {
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer
<< NodeType::MetavoxelServer;
- Assignment* matchingStaticAssignment = NULL;
+ 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)))
+ || (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))
+ || nodeList->getInstance()->nodeWithUUID(nodeUUID))
{
SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID,
nodeType,
@@ -167,19 +278,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;
@@ -210,34 +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);
- Assignment* 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());
-
- if (assignmentToDeploy->getNumberOfInstances() == 0) {
- // there are no more instances of this script to send out, delete it
- delete assignmentToDeploy;
- }
- }
+ 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;
}
}
}
@@ -281,70 +381,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";
@@ -373,24 +409,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;
@@ -428,11 +459,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";
@@ -466,10 +494,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
- _assignmentQueueMutex.lock();
- _assignmentQueue.push_back(scriptAssignment);
- _assignmentQueueMutex.unlock();
+ _assignmentQueue.enqueue(SharedAssignmentPointer(scriptAssignment));
}
} else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) {
if (path.startsWith(URI_NODE)) {
@@ -504,307 +529,137 @@ 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
- _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
- 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);
+
+ // 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 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.isEmpty() ? NULL : assignmentPool.toLocal8Bit().constData()));
-
- 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.isEmpty() ? NULL : assignmentPool.toLocal8Bit().constData()));
-
- 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) {
- _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;
+ // look for a match in the assignment hash
+
+ QQueue::iterator i = _assignmentQueue.begin();
+
+ while (i != _assignmentQueue.end()) {
+ if (i->data()->getType() == Assignment::typeForNodeType(nodeType) && i->data()->getUUID() == checkInUUID) {
+ return _assignmentQueue.takeAt(i - _assignmentQueue.begin());
} else {
- // no match, push deque iterator forwards
- assignment++;
+ ++i;
}
}
-
- _assignmentQueueMutex.unlock();
} 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) {
- _assignmentQueueMutex.lock();
-
+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
- _assignmentQueueMutex.unlock();
- return deployableAssignment;
} else {
// push forward the iterator to check the next assignment
- assignment++;
+ ++sharedAssignment;
}
}
-
- _assignmentQueueMutex.unlock();
- return NULL;
+
+ return SharedAssignmentPointer();
}
-void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) {
-
- _assignmentQueueMutex.lock();
-
- 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;
}
}
-
- _assignmentQueueMutex.unlock();
-}
-
-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;
// 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 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;
-
- 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];
-
- _assignmentQueueMutex.lock();
- _assignmentQueue.push_back(&_staticAssignments[i]);
- _assignmentQueueMutex.unlock();
+ 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 26cdc765ba..60251b3bb4 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,37 +34,27 @@ 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);
- bool checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket,
- const HifiSockAddr& nodeLocalSocket,
- const QUuid& checkInUUI);
- void addReleasedAssignmentBackToQueue(Assignment* releasedAssignment);
+ 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);
+ void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment);
HTTPManager _HTTPManager;
- QMutex _assignmentQueueMutex;
- 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/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..81ccfe108b 100644
--- a/examples/collidingParticles.js
+++ b/examples/collidingParticles.js
@@ -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 c1b33b24a5..43eb516cee 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");
}
@@ -73,18 +82,106 @@ 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);
-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);
@@ -102,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..152bb18fca 100644
--- a/examples/editParticleExample.js
+++ b/examples/editParticleExample.js
@@ -44,7 +44,6 @@ var particleID = Particles.addParticle(originalProperties);
function moveParticle() {
if (count >= moveUntil) {
- //Agent.stop();
// delete it...
if (count == moveUntil) {
@@ -54,8 +53,8 @@ function moveParticle() {
// stop it...
if (count >= stopAfter) {
- print("calling Agent.stop()");
- Agent.stop();
+ print("calling Script.stop()");
+ Script.stop();
}
count++;
@@ -86,5 +85,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 f582ee6469..5eb257d502 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.
@@ -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
new file mode 100644
index 0000000000..6779941dc7
--- /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");
+Script.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..e7cd2973e2 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'); " +
" } " +
@@ -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 0cbe3ff366..56e916a183 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'); " +
" } " +
@@ -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
new file mode 100644
index 0000000000..b2b6627063
--- /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 {
+ Script.stop();
+ }
+
+ iteration++;
+ print("iteration="+iteration);
+}
+
+
+// register the call back so it fires before each data send
+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
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 09e4c1ca62..a8e5a540fd 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),
@@ -1090,7 +1089,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();
@@ -1410,10 +1409,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
@@ -1670,7 +1669,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.");
@@ -1810,8 +1814,6 @@ void Application::init() {
_sharedVoxelSystem.changeTree(&_clipboard);
delete tmpTree;
- _voxelImporter.init(_settings);
-
_environment.init();
_glowEffect.init();
@@ -1875,6 +1877,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);
@@ -3842,18 +3855,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/Application.h b/interface/src/Application.h
index 111110296f..bf9981a160 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();
@@ -353,7 +353,7 @@ private:
VoxelSystem _voxels;
VoxelTree _clipboard; // if I copy/paste
- VoxelImporter _voxelImporter;
+ VoxelImporter* _voxelImporter;
VoxelSystem _sharedVoxelSystem;
ViewFrustum _sharedVoxelSystemViewFrustum;
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);
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/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";
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) {
diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 78b8bad3ed..d98d30cf6a 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -162,13 +162,13 @@ 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)
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);
@@ -189,15 +189,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,
- 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;
}
}
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) {
diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp
index 8a7f839b70..d128206c80 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;
@@ -1106,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()) {
diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp
index a8906f9167..98afa76107 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* startPosition = reinterpret_cast(packet.data());
+ const unsigned char* sourceBuffer = startPosition + 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) {
diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp
index d947b894aa..5a923eea93 100644
--- a/libraries/avatars/src/HandData.cpp
+++ b/libraries/avatars/src/HandData.cpp
@@ -160,31 +160,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 +185,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 +209,11 @@ 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();
+
+ return sourceBuffer - startPosition;
}
void HandData::setFingerTrailLength(unsigned int length) {
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 {
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(" ");
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++;
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++;
diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp
index 51b73a9ed2..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,13 +97,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;
-
// 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;
diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp
index 1f6829e29a..bb190aa32f 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
@@ -830,7 +832,7 @@ void Particle::update(const quint64& 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) {
@@ -852,106 +854,62 @@ void Particle::update(const quint64& 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) {
quint64 ageInUsecs = age * USECS_PER_SECOND;
_created = usecTimestampNow() - ageInUsecs;
diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h
index debb073ebd..925227055f 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 275ac542a2..b5fe827ebb 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/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));
diff --git a/libraries/particles/src/ParticlesScriptingInterface.h b/libraries/particles/src/ParticlesScriptingInterface.h
index dc5793ae30..729561571e 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(PacketType packetType, ParticleID particleID, const ParticleProperties& properties);
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;
};
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 71e450d4ad..9a7a9197b0 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
@@ -41,6 +42,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)
{
@@ -114,10 +116,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);
@@ -129,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 ef55e14109..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,
@@ -41,10 +39,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/Assignment.cpp b/libraries/shared/src/Assignment.cpp
index 2bff4ddcd0..83296991f3 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:
@@ -55,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),
@@ -85,20 +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;
-
- if (!packetStream.atEnd()) {
- _payload = packet.mid(packetStream.device()->pos());
- }
+ packetStream >> *this;
}
#ifdef WIN32
@@ -159,18 +144,26 @@ 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();
+
+ if (!assignment.getPool().isEmpty()) {
+ debug << ", Pool: " << assignment.getPool();
+ }
+
+ return debug.space();
}
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 418ea7fe09..dd34751b57 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; }
@@ -92,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
diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp
index c5ad709fa4..cd9356ab15 100644
--- a/libraries/shared/src/NodeList.cpp
+++ b/libraries/shared/src/NodeList.cpp
@@ -119,13 +119,13 @@ 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();
+ quint64 now = usecTimestampNow();
int pingTime = now - ourOriginalTime;
int oneWayFlightTime = pingTime / 2; // half of the ping is our one way flight
@@ -554,8 +554,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);
@@ -621,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()) {
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);
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 4788582102..3b869e0ece 100644
--- a/libraries/shared/src/SharedUtil.cpp
+++ b/libraries/shared/src/SharedUtil.cpp
@@ -231,7 +231,6 @@ void sharedMessageHandler(QtMsgType type, const QMessageLogContext& context, con
fprintf(stdout, "%s", message.toLocal8Bit().constData());
}
-
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 f47a9eea1e..c982ab3596 100644
--- a/libraries/shared/src/SharedUtil.h
+++ b/libraries/shared/src/SharedUtil.h
@@ -96,20 +96,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);
-
#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 3ea4ca3626..fea75abf23 100644
--- a/libraries/voxels/src/VoxelEditPacketSender.cpp
+++ b/libraries/voxels/src/VoxelEditPacketSender.cpp
@@ -70,14 +70,14 @@ bool createVoxelEditMessage(PacketType command, short int sequence,
// 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;
}
diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h
index 79d9f8c757..90085635b0 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 dc53840cb1..877383e0b0 100644
--- a/libraries/voxels/src/VoxelsScriptingInterface.h
+++ b/libraries/voxels/src/VoxelsScriptingInterface.h
@@ -57,20 +57,4 @@ private:
void queueVoxelAdd(PacketType 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__) */