Merge branch 'master' of https://github.com/worklist/hifi into multi_VS_assigments

This commit is contained in:
ZappoMan 2013-09-17 12:18:51 -07:00
commit ad4dea129c
21 changed files with 217 additions and 71 deletions

View file

@ -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"

View file

@ -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})
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})

View file

@ -9,11 +9,11 @@
#include <QtScript/QScriptEngine>
#include <QtNetwork/QtNetwork>
#include <AvatarData.h>
#include <NodeList.h>
#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);

View file

@ -16,8 +16,8 @@
#include "Agent.h"
#include <Assignment.h>
#include <AudioMixer.h>
#include <AvatarMixer.h>
#include "audio/AudioMixer.h"
#include "avatars/AvatarMixer.h"
#include <Logging.h>
#include <NodeList.h>
#include <PacketHeaders.h>
@ -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);

View file

@ -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);
}

View file

@ -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 <QtCore/QObject>
#include <VoxelEditPacketSender.h>
/// 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__) */

View file

@ -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)) {

View file

@ -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})

View file

@ -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;

View file

@ -14,6 +14,9 @@
Run
</a>
</div>
<div class='big-field' id='instance-field'>
<input type='text' name='instances' placeholder='# of instances'>
</div>
<!-- %div#stop-button.big-button -->
</body>
</html>

View file

@ -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);

View file

@ -111,9 +111,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
@ -129,7 +140,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[]) {
@ -355,25 +365,39 @@ int main(int argc, const char* argv[]) {
std::deque<Assignment*>::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();
@ -397,12 +421,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

View file

@ -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})
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})

View file

@ -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);

View file

@ -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);