diff --git a/VoxelScriptingInterface.cpp b/VoxelScriptingInterface.cpp new file mode 100644 index 0000000000..901bb06750 --- /dev/null +++ b/VoxelScriptingInterface.cpp @@ -0,0 +1,9 @@ +// +// VoxelScriptingInterface.cpp +// hifi +// +// Created by Stephen Birarda on 9/17/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include "VoxelScriptingInterface.h" diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 39d1eecca6..ad01750aa1 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -24,4 +24,12 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(voxel-server-library ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file +link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(voxel-server-library ${TARGET_NAME} ${ROOT_DIR}) + +# link the stk library +set(STK_ROOT_DIR ${ROOT_DIR}/externals/stk) +find_package(STK REQUIRED) +target_link_libraries(${TARGET_NAME} ${STK_LIBRARIES}) +include_directories(${STK_INCLUDE_DIRS}) + diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 3b56a6b0b7..ac6f1eca4f 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -9,11 +9,11 @@ #include #include +#include #include -#include "AvatarData.h" - #include "Agent.h" +#include "voxels/VoxelScriptingInterface.h" Agent::Agent() : _shouldStop(false) @@ -23,7 +23,7 @@ Agent::Agent() : void Agent::run(QUrl scriptURL) { NodeList::getInstance()->setOwnerType(NODE_TYPE_AGENT); - NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_AVATAR_MIXER, 1); + NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_VOXEL_SERVER, 1); QNetworkAccessManager manager; @@ -39,14 +39,13 @@ void Agent::run(QUrl scriptURL) { QScriptEngine engine; - AvatarData *testAvatarData = new AvatarData; - - QScriptValue avatarDataValue = engine.newQObject(testAvatarData); - engine.globalObject().setProperty("Avatar", avatarDataValue); - QScriptValue agentValue = engine.newQObject(this); engine.globalObject().setProperty("Agent", agentValue); + VoxelScriptingInterface voxelScripter; + QScriptValue voxelScripterValue = engine.newQObject(&voxelScripter); + engine.globalObject().setProperty("Voxels", voxelScripterValue); + qDebug() << "Downloaded script:" << scriptString << "\n"; qDebug() << "Evaluated script:" << engine.evaluate(scriptString).toString() << "\n"; @@ -75,9 +74,10 @@ void Agent::run(QUrl scriptURL) { NodeList::getInstance()->sendDomainServerCheckIn(); } + // allow the scripter's call back to setup visual data emit preSendCallback(); - - testAvatarData->sendData(); + // flush the voxel packet queue + voxelScripter.getVoxelPacketSender()->process(); if (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) { NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); diff --git a/libraries/audio/src/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp similarity index 100% rename from libraries/audio/src/AudioMixer.cpp rename to assignment-client/src/audio/AudioMixer.cpp diff --git a/libraries/audio/src/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h similarity index 100% rename from libraries/audio/src/AudioMixer.h rename to assignment-client/src/audio/AudioMixer.h diff --git a/libraries/audio/src/AvatarAudioRingBuffer.cpp b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp similarity index 100% rename from libraries/audio/src/AvatarAudioRingBuffer.cpp rename to assignment-client/src/audio/AvatarAudioRingBuffer.cpp diff --git a/libraries/audio/src/AvatarAudioRingBuffer.h b/assignment-client/src/audio/AvatarAudioRingBuffer.h similarity index 100% rename from libraries/audio/src/AvatarAudioRingBuffer.h rename to assignment-client/src/audio/AvatarAudioRingBuffer.h diff --git a/libraries/avatars/src/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp similarity index 100% rename from libraries/avatars/src/AvatarMixer.cpp rename to assignment-client/src/avatars/AvatarMixer.cpp diff --git a/libraries/avatars/src/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h similarity index 100% rename from libraries/avatars/src/AvatarMixer.h rename to assignment-client/src/avatars/AvatarMixer.h diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 63943c97b5..76fb99839a 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -16,8 +16,8 @@ #include "Agent.h" #include -#include -#include +#include "audio/AudioMixer.h" +#include "avatars/AvatarMixer.h" #include #include #include @@ -31,6 +31,7 @@ const char CHILD_TARGET_NAME[] = "assignment-client"; pid_t* childForks = NULL; sockaddr_in customAssignmentSocket = {}; int numForks = 0; +Assignment::Type overiddenAssignmentType = Assignment::AllTypes; void childClient() { // this is one of the child forks or there is a single assignment client, continue assignment-client execution @@ -56,8 +57,8 @@ void childClient() { sockaddr_in senderSocket = {}; - // create a request assignment, accept all assignments, pass the desired pool (if it exists) - Assignment requestAssignment(Assignment::RequestCommand, Assignment::AllTypes); + // create a request assignment, accept assignments defined by the overidden type + Assignment requestAssignment(Assignment::RequestCommand, ::overiddenAssignmentType); while (true) { if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { @@ -211,6 +212,15 @@ int main(int argc, const char* argv[]) { ::customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServerHostname, assignmentServerPort); } + const char ASSIGNMENT_TYPE_OVVERIDE_OPTION[] = "-t"; + const char* assignmentTypeString = getCmdOption(argc, argv, ASSIGNMENT_TYPE_OVVERIDE_OPTION); + + if (assignmentTypeString) { + // the user is asking to only be assigned to a particular type of assignment + // so set that as the ::overridenAssignmentType to be used in requests + ::overiddenAssignmentType = (Assignment::Type) atoi(assignmentTypeString); + } + const char* NUM_FORKS_PARAMETER = "-n"; const char* numForksString = getCmdOption(argc, argv, NUM_FORKS_PARAMETER); diff --git a/assignment-client/src/voxels/VoxelScriptingInterface.cpp b/assignment-client/src/voxels/VoxelScriptingInterface.cpp new file mode 100644 index 0000000000..343cb01a44 --- /dev/null +++ b/assignment-client/src/voxels/VoxelScriptingInterface.cpp @@ -0,0 +1,15 @@ +// +// VoxelScriptingInterface.cpp +// hifi +// +// Created by Stephen Birarda on 9/17/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include "VoxelScriptingInterface.h" + +void VoxelScriptingInterface::queueVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { + // setup a VoxelDetail struct with the data + VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; + _voxelPacketSender.sendVoxelEditMessage(PACKET_TYPE_SET_VOXEL, addVoxelDetail); +} diff --git a/assignment-client/src/voxels/VoxelScriptingInterface.h b/assignment-client/src/voxels/VoxelScriptingInterface.h new file mode 100644 index 0000000000..00be3d536f --- /dev/null +++ b/assignment-client/src/voxels/VoxelScriptingInterface.h @@ -0,0 +1,36 @@ +// +// VoxelScriptingInterface.h +// hifi +// +// Created by Stephen Birarda on 9/17/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__VoxelScriptingInterface__ +#define __hifi__VoxelScriptingInterface__ + +#include + +#include + +/// handles scripting of voxel commands from JS passed to assigned clients +class VoxelScriptingInterface : public QObject { + Q_OBJECT +public: + VoxelEditPacketSender* getVoxelPacketSender() { return &_voxelPacketSender; } +public slots: + /// queues the creation of a voxel which will be sent by calling process on the PacketSender + /// \param x the x-coordinate of the voxel (in VS space) + /// \param y the y-coordinate of the voxel (in VS space) + /// \param z the z-coordinate of the voxel (in VS space) + /// \param scale the scale of the voxel (in VS space) + /// \param red the R value for RGB color of voxel + /// \param green the G value for RGB color of voxel + /// \param blue the B value for RGB color of voxel + void queueVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue); +private: + /// attached VoxelEditPacketSender that handles queuing and sending of packets to VS + VoxelEditPacketSender _voxelPacketSender; +}; + +#endif /* defined(__hifi__VoxelScriptingInterface__) */ diff --git a/assignment-server/src/main.cpp b/assignment-server/src/main.cpp index caec59cd77..db335008a5 100644 --- a/assignment-server/src/main.cpp +++ b/assignment-server/src/main.cpp @@ -62,30 +62,39 @@ int main(int argc, const char* argv[]) { continue; } - // check if the requestor is on the same network as the destination for the assignment - if (senderSocket.sin_addr.s_addr == - ((sockaddr_in*) (*assignment)->getAttachedPublicSocket())->sin_addr.s_addr) { - // if this is the case we remove the public socket on the assignment by setting it to NULL - // this ensures the local IP and port sent to the requestor is the local address of destination - (*assignment)->setAttachedPublicSocket(NULL); + if (requestAssignment.getType() == Assignment::AllTypes || + (*assignment)->getType() == requestAssignment.getType()) { + // give this assignment out, either we have a type match or the requestor has said they will + // take all types + + // check if the requestor is on the same network as the destination for the assignment + if (senderSocket.sin_addr.s_addr == + ((sockaddr_in*) (*assignment)->getAttachedPublicSocket())->sin_addr.s_addr) { + // if this is the case we remove the public socket on the assignment by setting it to NULL + // this ensures the local IP and port sent to the requestor is the local address of destination + (*assignment)->setAttachedPublicSocket(NULL); + } + + + int numAssignmentBytes = (*assignment)->packToBuffer(assignmentPacket + numSendHeaderBytes); + + // send the assignment + serverSocket.send((sockaddr*) &senderSocket, + assignmentPacket, + numSendHeaderBytes + numAssignmentBytes); + + + // delete this assignment now that it has been sent out + delete *assignment; + // remove it from the deque and make the iterator the next assignment + assignmentQueue.erase(assignment); + + // stop looping - we've handed out an assignment + break; + } else { + // push forward the iterator to check the next assignment + assignment++; } - - - int numAssignmentBytes = (*assignment)->packToBuffer(assignmentPacket + numSendHeaderBytes); - - // send the assignment - serverSocket.send((sockaddr*) &senderSocket, - assignmentPacket, - numSendHeaderBytes + numAssignmentBytes); - - - // delete this assignment now that it has been sent out - delete *assignment; - // remove it from the deque and make the iterator the next assignment - assignmentQueue.erase(assignment); - - // stop looping - we've handed out an assignment - break; } } } else if (senderData[0] == PACKET_TYPE_CREATE_ASSIGNMENT && packetVersionMatch(senderData)) { diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index 8b2bcb542c..e828e68be2 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -2,7 +2,15 @@ MACRO(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) project(${TARGET}) # grab the implemenation and header files - file(GLOB TARGET_SRCS src/*.cpp src/*.h src/*.c) + file(GLOB TARGET_SRCS src/*) + + file(GLOB SRC_SUBDIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/*) + foreach(DIR ${SRC_SUBDIRS}) + if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/${DIR}) + FILE(GLOB DIR_CONTENTS src/${DIR}/*) + SET(TARGET_SRCS ${TARGET_SRCS} ${DIR_CONTENTS}) + endif() + endforeach() # add the executable add_executable(${TARGET} ${TARGET_SRCS}) diff --git a/domain-server/resources/web/assignment/css/style.css b/domain-server/resources/web/assignment/css/style.css index 000f2eff67..b6c26ca9fd 100644 --- a/domain-server/resources/web/assignment/css/style.css +++ b/domain-server/resources/web/assignment/css/style.css @@ -36,11 +36,22 @@ body { } #deploy-button { background-color: #0DFFBB; - right: 0px; + right: 85px; } #deploy-button:hover { background-color: #28FF57; } + +#instance-field { + position: absolute; + right: 20px; + top: 40px; +} + +#instance-field input { + width: 80px; +} + #stop-button { background-color: #CC1F00; right: 0px; diff --git a/domain-server/resources/web/assignment/index.shtml b/domain-server/resources/web/assignment/index.shtml index fe47b818ed..0bc0e67eef 100644 --- a/domain-server/resources/web/assignment/index.shtml +++ b/domain-server/resources/web/assignment/index.shtml @@ -14,6 +14,9 @@ Run +
+ +
diff --git a/domain-server/resources/web/assignment/js/assignment.js b/domain-server/resources/web/assignment/js/assignment.js index 630acd4847..a34f539961 100644 --- a/domain-server/resources/web/assignment/js/assignment.js +++ b/domain-server/resources/web/assignment/js/assignment.js @@ -20,6 +20,11 @@ $(document).ready(function(){ // add the script + script + '\r\n' + '--' + boundary + '--'; + + var headers = {}; + if ($('#instance-field input').val()) { + headers['ASSIGNMENT-INSTANCES'] = $('#instance-field input').val(); + } // post form to assignment in order to create an assignment $.ajax({ @@ -27,6 +32,7 @@ $(document).ready(function(){ data: body, type: "POST", url: "/assignment", + headers: headers, success: function (data, status) { console.log(data); console.log(status); diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 044ea0b369..62d8be42b7 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -76,9 +76,20 @@ static int mongooseRequestHandler(struct mg_connection *conn) { const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment"; static void mongooseUploadHandler(struct mg_connection *conn, const char *path) { + // create an assignment for this saved script, for now make it local only Assignment *scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType, Assignment::LocalLocation); + // check how many instances of this assignment the user wants by checking the ASSIGNMENT-INSTANCES header + const char ASSIGNMENT_INSTANCES_HTTP_HEADER[] = "ASSIGNMENT-INSTANCES"; + const char *requestInstancesHeader = mg_get_header(conn, ASSIGNMENT_INSTANCES_HTTP_HEADER); + + if (requestInstancesHeader) { + // the user has requested a number of instances greater than 1 + // so set that on the created assignment + scriptAssignment->setNumberOfInstances(atoi(requestInstancesHeader)); + } + QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION); newPath += "/"; // append the UUID for this script as the new filename, remove the curly braces @@ -94,7 +105,6 @@ static void mongooseUploadHandler(struct mg_connection *conn, const char *path) ::assignmentQueueMutex.lock(); ::assignmentQueue.push_back(scriptAssignment); ::assignmentQueueMutex.unlock(); - } int main(int argc, const char* argv[]) { @@ -320,25 +330,39 @@ int main(int argc, const char* argv[]) { std::deque::iterator assignment = ::assignmentQueue.begin(); while (assignment != ::assignmentQueue.end()) { + // construct the requested assignment from the packet data + Assignment requestAssignment(packetData, receivedBytes); - // give this assignment out, no conditions stop us from giving it to the local assignment client - int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT); - int numAssignmentBytes = (*assignment)->packToBuffer(broadcastPacket + numHeaderBytes); - - nodeList->getNodeSocket()->send((sockaddr*) &nodePublicAddress, - broadcastPacket, - numHeaderBytes + numAssignmentBytes); - - // remove the assignment from the queue - ::assignmentQueue.erase(assignment); - - if ((*assignment)->getType() == Assignment::AgentType) { - // if this is a script assignment we need to delete it to avoid a memory leak - delete *assignment; + if (requestAssignment.getType() == Assignment::AllTypes || + (*assignment)->getType() == requestAssignment.getType()) { + // give this assignment out, either the type matches or the requestor said they will take any + int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT); + int numAssignmentBytes = (*assignment)->packToBuffer(broadcastPacket + numHeaderBytes); + + nodeList->getNodeSocket()->send((sockaddr*) &nodePublicAddress, + broadcastPacket, + numHeaderBytes + numAssignmentBytes); + + if ((*assignment)->getType() == Assignment::AgentType) { + // if this is a script assignment we need to delete it to avoid a memory leak + // or if there is more than one instance to send out, simpy decrease the number of instances + if ((*assignment)->getNumberOfInstances() > 1) { + (*assignment)->decrementNumberOfInstances(); + } else { + ::assignmentQueue.erase(assignment); + delete *assignment; + } + } else { + // remove the assignment from the queue + ::assignmentQueue.erase(assignment); + } + + // stop looping, we've handed out an assignment + break; + } else { + // push forward the iterator to check the next assignment + assignment++; } - - // stop looping, we've handed out an assignment - break; } ::assignmentQueueMutex.unlock(); @@ -362,12 +386,18 @@ int main(int argc, const char* argv[]) { nodeList->sendAssignment(*(*assignment)); - // remove the assignment from the queue - ::assignmentQueue.erase(assignment); - if ((*assignment)->getType() == Assignment::AgentType) { // if this is a script assignment we need to delete it to avoid a memory leak - delete *assignment; + // or if there is more than one instance to send out, simpy decrease the number of instances + if ((*assignment)->getNumberOfInstances() > 1) { + (*assignment)->decrementNumberOfInstances(); + } else { + ::assignmentQueue.erase(assignment); + delete *assignment; + } + } else { + // remove the assignment from the queue + ::assignmentQueue.erase(assignment); } // stop looping, we've handed out an assignment diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index 6c458149bc..2d82fff1e1 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -16,10 +16,4 @@ include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -# link the stk library -set(STK_ROOT_DIR ${ROOT_DIR}/externals/stk) -find_package(STK REQUIRED) -target_link_libraries(${TARGET_NAME} ${STK_LIBRARIES}) -include_directories(${STK_INCLUDE_DIRS}) \ No newline at end of file +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index 8f6d20db9e..d794495c29 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -21,7 +21,8 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, Assig _type(type), _location(location), _attachedPublicSocket(NULL), - _attachedLocalSocket(NULL) + _attachedLocalSocket(NULL), + _numberOfInstances(1) { // set the create time on this assignment gettimeofday(&_time, NULL); @@ -35,7 +36,8 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, Assig Assignment::Assignment(const unsigned char* dataBuffer, int numBytes) : _location(GlobalLocation), _attachedPublicSocket(NULL), - _attachedLocalSocket(NULL) + _attachedLocalSocket(NULL), + _numberOfInstances(1) { // set the create time on this assignment gettimeofday(&_time, NULL); diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index 4fdbeed838..59e2c45db7 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -56,6 +56,10 @@ public: Assignment::Location getLocation() const { return _location; } const timeval& getTime() const { return _time; } + int getNumberOfInstances() const { return _numberOfInstances; } + void setNumberOfInstances(int numberOfInstances) { _numberOfInstances = numberOfInstances; } + void decrementNumberOfInstances() { --_numberOfInstances; } + const sockaddr* getAttachedPublicSocket() { return _attachedPublicSocket; } void setAttachedPublicSocket(const sockaddr* attachedPublicSocket); @@ -78,6 +82,7 @@ private: sockaddr* _attachedPublicSocket; /// pointer to a public socket that relates to assignment, depends on direction sockaddr* _attachedLocalSocket; /// pointer to a local socket that relates to assignment, depends on direction timeval _time; /// time the assignment was created (set in constructor) + int _numberOfInstances; /// the number of instances of this assignment }; QDebug operator<<(QDebug debug, const Assignment &assignment);