diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index a77be03aa5..de64f8c38d 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -159,7 +159,7 @@ static void renderMovingBug() { } // send the "erase message" first... - PACKET_TYPE message = PACKET_TYPE_ERASE_VOXEL; + PACKET_TYPE message = PACKET_TYPE_VOXEL_ERASE; ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_BUG, (VoxelDetail*)&details); // Move the bug... @@ -219,7 +219,7 @@ static void renderMovingBug() { } // send the "create message" ... - message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; + message = PACKET_TYPE_VOXEL_SET_DESTRUCTIVE; ::voxelEditPacketSender->queueVoxelEditMessages(message, VOXELS_PER_BUG, (VoxelDetail*)&details); } @@ -254,7 +254,7 @@ static void sendVoxelBlinkMessage() { detail.green = 0 * ::intensity; detail.blue = 0 * ::intensity; - PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; + PACKET_TYPE message = PACKET_TYPE_VOXEL_SET_DESTRUCTIVE; ::voxelEditPacketSender->sendVoxelEditMessage(message, detail); } @@ -271,7 +271,7 @@ unsigned char onColor[3] = { 0, 255, 255 }; const float STRING_OF_LIGHTS_SIZE = 0.125f / TREE_SCALE; // approximately 1/8th meter static void sendBlinkingStringOfLights() { - PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully! + PACKET_TYPE message = PACKET_TYPE_VOXEL_SET_DESTRUCTIVE; // we're a bully! float lightScale = STRING_OF_LIGHTS_SIZE; static VoxelDetail details[LIGHTS_PER_SEGMENT]; @@ -377,7 +377,7 @@ const int PACKETS_PER_DANCE_FLOOR = DANCE_FLOOR_VOXELS_PER_PACKET / (DANCE_FLOOR int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH]; void sendDanceFloor() { - PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully! + PACKET_TYPE message = PACKET_TYPE_VOXEL_SET_DESTRUCTIVE; // we're a bully! float lightScale = DANCE_FLOOR_LIGHT_SIZE; static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET]; @@ -493,7 +493,7 @@ bool billboardMessage[BILLBOARD_HEIGHT][BILLBOARD_WIDTH] = { }; static void sendBillboard() { - PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully! + PACKET_TYPE message = PACKET_TYPE_VOXEL_SET_DESTRUCTIVE; // we're a bully! float lightScale = BILLBOARD_LIGHT_SIZE; static VoxelDetail details[VOXELS_PER_PACKET]; @@ -564,7 +564,7 @@ void doBuildStreet() { return; } - PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully! + PACKET_TYPE message = PACKET_TYPE_VOXEL_SET_DESTRUCTIVE; // we're a bully! static VoxelDetail details[BRICKS_PER_PACKET]; for (int z = 0; z < ROAD_LENGTH; z++) { @@ -864,7 +864,7 @@ int main(int argc, const char * argv[]) nodeSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { - if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { + if (packetData[0] == PACKET_TYPE_JURISDICTION) { if (::jurisdictionListener) { ::jurisdictionListener->queueReceivedPacket(nodeSockAddr, packetData, receivedBytes); } diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 5ba5a1d4e4..5bc4829117 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -26,7 +26,11 @@ link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(voxel-server-library ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(particle-server ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(voxel-server ${TARGET_NAME} ${ROOT_DIR}) +#testing include_directories(${ROOT_DIR}/externals/civetweb/include) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 95c3f91311..b4a0f3f52f 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -40,7 +40,7 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) { } void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { - if (dataByteArray[0] == PACKET_TYPE_VOXEL_JURISDICTION) { + if (dataByteArray[0] == PACKET_TYPE_JURISDICTION) { _voxelScriptingInterface.getJurisdictionListener()->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); diff --git a/assignment-client/src/AssignmentFactory.cpp b/assignment-client/src/AssignmentFactory.cpp index aa173f920f..815186c4f5 100644 --- a/assignment-client/src/AssignmentFactory.cpp +++ b/assignment-client/src/AssignmentFactory.cpp @@ -12,6 +12,7 @@ #include "audio/AudioMixer.h" #include "avatars/AvatarMixer.h" #include +#include #include "AssignmentFactory.h" @@ -30,6 +31,8 @@ ThreadedAssignment* AssignmentFactory::unpackAssignment(const unsigned char* dat return new Agent(dataBuffer, numBytes); case Assignment::VoxelServerType: return new VoxelServer(dataBuffer, numBytes); + case Assignment::ParticleServerType: + return new ParticleServer(dataBuffer, numBytes); default: return NULL; } diff --git a/assignment-client/src/voxels/VoxelScriptingInterface.cpp b/assignment-client/src/voxels/VoxelScriptingInterface.cpp index 1801c621c4..90755f8c65 100644 --- a/assignment-client/src/voxels/VoxelScriptingInterface.cpp +++ b/assignment-client/src/voxels/VoxelScriptingInterface.cpp @@ -22,7 +22,7 @@ void VoxelScriptingInterface::queueVoxelAdd(float x, float y, float z, float sca VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; // queue the packet - queueVoxelAdd(PACKET_TYPE_SET_VOXEL, addVoxelDetail); + queueVoxelAdd(PACKET_TYPE_VOXEL_SET, addVoxelDetail); } void VoxelScriptingInterface::queueDestructiveVoxelAdd(float x, float y, float z, float scale, @@ -31,7 +31,7 @@ void VoxelScriptingInterface::queueDestructiveVoxelAdd(float x, float y, float z VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; // queue the destructive add - queueVoxelAdd(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE, addVoxelDetail); + queueVoxelAdd(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, addVoxelDetail); } void VoxelScriptingInterface::queueVoxelDelete(float x, float y, float z, float scale) { @@ -39,6 +39,6 @@ void VoxelScriptingInterface::queueVoxelDelete(float x, float y, float z, float // setup a VoxelDetail struct with data VoxelDetail deleteVoxelDetail = {x, y, z, scale, 0, 0, 0}; - _voxelPacketSender.queueVoxelEditMessages(PACKET_TYPE_ERASE_VOXEL, 1, &deleteVoxelDetail); + _voxelPacketSender.queueVoxelEditMessages(PACKET_TYPE_VOXEL_ERASE, 1, &deleteVoxelDetail); } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b10006e6cc..4f476947a9 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -318,6 +318,9 @@ DomainServer::DomainServer(int argc, char* argv[]) : const char VOXEL_CONFIG_OPTION[] = "--voxelServerConfig"; _voxelServerConfig = getCmdOption(argc, (const char**) argv, VOXEL_CONFIG_OPTION); + + const char PARTICLE_CONFIG_OPTION[] = "--particleServerConfig"; + _particleServerConfig = getCmdOption(argc, (const char**) argv, PARTICLE_CONFIG_OPTION); // setup the mongoose web server struct mg_callbacks callbacks = {}; @@ -390,6 +393,48 @@ void DomainServer::prepopulateStaticAssignmentFile() { Assignment rootVoxelServerAssignment(Assignment::CreateCommand, Assignment::VoxelServerType); freshStaticAssignments[numFreshStaticAssignments++] = rootVoxelServerAssignment; } + + // Handle Domain/Particle Server configuration command line arguments + if (_particleServerConfig) { + qDebug("Reading Particle Server Configuration.\n"); + qDebug() << "config: " << _particleServerConfig << "\n"; + + 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\n", 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 << "\n"; + } + + Assignment particleServerAssignment(Assignment::CreateCommand, + Assignment::ParticleServerType, + (assignmentPool.isEmpty() ? NULL : assignmentPool.toLocal8Bit().constData())); + + int payloadLength = config.length() + sizeof(char); + particleServerAssignment.setPayload((uchar*)config.toLocal8Bit().constData(), payloadLength); + + freshStaticAssignments[numFreshStaticAssignments++] = particleServerAssignment; + } + } else { + Assignment rootParticleServerAssignment(Assignment::CreateCommand, Assignment::ParticleServerType); + freshStaticAssignments[numFreshStaticAssignments++] = rootParticleServerAssignment; + } qDebug() << "Adding" << numFreshStaticAssignments << "static assignments to fresh file.\n"; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 755f73485c..7d63409be0 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -64,6 +64,7 @@ private: Assignment* _staticAssignments; const char* _voxelServerConfig; + const char* _particleServerConfig; bool _hasCompletedRestartHold; }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 833f811bf8..d8c8f64539 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1478,7 +1478,7 @@ void Application::removeVoxel(glm::vec3 position, voxel.y = position.y / TREE_SCALE; voxel.z = position.z / TREE_SCALE; voxel.s = scale / TREE_SCALE; - _voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, voxel); + _voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_VOXEL_ERASE, voxel); // delete it locally to see the effect immediately (and in case no voxel server is present) _voxels.deleteVoxelAt(voxel.x, voxel.y, voxel.z, voxel.s); @@ -1498,7 +1498,7 @@ void Application::makeVoxel(glm::vec3 position, voxel.red = red; voxel.green = green; voxel.blue = blue; - PACKET_TYPE message = isDestructive ? PACKET_TYPE_SET_VOXEL_DESTRUCTIVE : PACKET_TYPE_SET_VOXEL; + PACKET_TYPE message = isDestructive ? PACKET_TYPE_VOXEL_SET_DESTRUCTIVE : PACKET_TYPE_VOXEL_SET; _voxelEditSender.sendVoxelEditMessage(message, voxel); // create the voxel locally so it appears immediately @@ -1580,7 +1580,7 @@ bool Application::sendVoxelsOperation(OctreeElement* element, void* extraData) { codeColorBuffer[bytesInCode + RED_INDEX] = voxel->getColor()[RED_INDEX]; codeColorBuffer[bytesInCode + GREEN_INDEX] = voxel->getColor()[GREEN_INDEX]; codeColorBuffer[bytesInCode + BLUE_INDEX] = voxel->getColor()[BLUE_INDEX]; - getInstance()->_voxelEditSender.queueVoxelEditMessage(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE, + getInstance()->_voxelEditSender.queueVoxelEditMessage(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, codeColorBuffer, codeAndColorLength); delete[] codeColorBuffer; @@ -3977,7 +3977,7 @@ bool Application::maybeEditVoxelUnderCursor() { void Application::deleteVoxelUnderCursor() { if (_mouseVoxel.s != 0) { // sending delete to the server is sufficient, server will send new version so we see updates soon enough - _voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, _mouseVoxel); + _voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_VOXEL_ERASE, _mouseVoxel); // delete it locally to see the effect immediately (and in case no voxel server is present) _voxels.deleteVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); @@ -4235,8 +4235,8 @@ void* Application::networkReceive(void* args) { app->_audio.addReceivedAudioToBuffer(app->_incomingPacket, bytesReceived); break; case PACKET_TYPE_VOXEL_DATA: - case PACKET_TYPE_ERASE_VOXEL: - case PACKET_TYPE_VOXEL_STATS: + case PACKET_TYPE_VOXEL_ERASE: + case PACKET_TYPE_OCTREE_STATS: case PACKET_TYPE_ENVIRONMENT_DATA: { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()"); diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index a591fbdbaa..0b0f5f5694 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -34,10 +34,10 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, uns app->_wantToKillLocalVoxels = false; } - // note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA - // immediately following them inside the same packet. So, we process the PACKET_TYPE_VOXEL_STATS first + // note: PACKET_TYPE_OCTREE_STATS can have PACKET_TYPE_VOXEL_DATA + // immediately following them inside the same packet. So, we process the PACKET_TYPE_OCTREE_STATS first // then process any remaining bytes as if it was another packet - if (packetData[0] == PACKET_TYPE_VOXEL_STATS) { + if (packetData[0] == PACKET_TYPE_OCTREE_STATS) { int statsMessageLength = app->parseVoxelStats(packetData, messageLength, senderSockAddr); wasStatsPacket = true; diff --git a/libraries/voxel-server-library/CMakeLists.txt b/libraries/octree-server/CMakeLists.txt similarity index 82% rename from libraries/voxel-server-library/CMakeLists.txt rename to libraries/octree-server/CMakeLists.txt index a44fffcc7c..d9ee7b0e2f 100644 --- a/libraries/voxel-server-library/CMakeLists.txt +++ b/libraries/octree-server/CMakeLists.txt @@ -6,7 +6,7 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") -set(TARGET_NAME voxel-server-library) +set(TARGET_NAME octree-server) find_package(Qt5Widgets REQUIRED) @@ -36,8 +36,7 @@ link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) # link in the hifi octree library link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) -# link in the hifi voxels library -link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) - -# link in the hifi avatars library -link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) +# link dl library on UNIX for civetweb +if (UNIX AND NOT APPLE) + target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) +endif (UNIX AND NOT APPLE) \ No newline at end of file diff --git a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp new file mode 100644 index 0000000000..61d2e6f6d8 --- /dev/null +++ b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp @@ -0,0 +1,168 @@ +// +// OctreeInboundPacketProcessor.cpp +// voxel-server +// +// Created by Brad Hefta-Gaub on 8/21/13 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// Threaded or non-threaded network packet processor for the voxel-server +// + +#include +#include + +#include "OctreeServer.h" +#include "OctreeServerConsts.h" +#include "OctreeInboundPacketProcessor.h" + +static QUuid DEFAULT_NODE_ID_REF; + +OctreeInboundPacketProcessor::OctreeInboundPacketProcessor(OctreeServer* myServer) : + _myServer(myServer), + _receivedPacketCount(0), + _totalTransitTime(0), + _totalProcessTime(0), + _totalLockWaitTime(0), + _totalElementsInPacket(0), + _totalPackets(0) +{ +} + +void OctreeInboundPacketProcessor::resetStats() { + _totalTransitTime = 0; + _totalProcessTime = 0; + _totalLockWaitTime = 0; + _totalElementsInPacket = 0; + _totalPackets = 0; + + _singleSenderStats.clear(); +} + + +void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, + unsigned char* packetData, ssize_t packetLength) { + + bool debugProcessPacket = _myServer->wantsVerboseDebug(); + + if (debugProcessPacket) { + printf("OctreeInboundPacketProcessor::processPacket() packetData=%p packetLength=%ld\n", packetData, packetLength); + } + + int numBytesPacketHeader = numBytesForPacketHeader(packetData); + + + // Ask our tree subclass if it can handle the incoming packet... + PACKET_TYPE packetType = packetData[0]; + if (_myServer->getOctree()->handlesEditPacketType(packetType)) { + PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE",debugProcessPacket); + _receivedPacketCount++; + + unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader))); + uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence)))); + uint64_t arrivedAt = usecTimestampNow(); + uint64_t transitTime = arrivedAt - sentAt; + int editsInPacket = 0; + uint64_t processTime = 0; + uint64_t lockWaitTime = 0; + + if (_myServer->wantsDebugReceiving()) { + printf("PROCESSING THREAD: got %c - %d command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n", + packetType, _receivedPacketCount, packetLength, sequence, transitTime); + } + int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt); + unsigned char* editData = (unsigned char*)&packetData[atByte]; + while (atByte < packetLength) { + int maxSize = packetLength - atByte; + + if (debugProcessPacket) { + printf("OctreeInboundPacketProcessor::processPacket() %c " + "packetData=%p packetLength=%ld voxelData=%p atByte=%d maxSize=%d\n", + packetType, packetData, packetLength, editData, atByte, maxSize); + } + + uint64_t startLock = usecTimestampNow(); + _myServer->getOctree()->lockForWrite(); + uint64_t startProcess = usecTimestampNow(); + int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType, + packetData, packetLength, editData, maxSize); + _myServer->getOctree()->unlock(); + uint64_t endProcess = usecTimestampNow(); + + editsInPacket++; + uint64_t thisProcessTime = endProcess - startProcess; + uint64_t thisLockWaitTime = startProcess - startLock; + processTime += thisProcessTime; + lockWaitTime += thisLockWaitTime; + + // skip to next voxel edit record in the packet + editData += editDataBytesRead; + atByte += editDataBytesRead; + } + + if (debugProcessPacket) { + printf("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %c " + "packetData=%p packetLength=%ld voxelData=%p atByte=%d\n", + packetType, packetData, packetLength, editData, atByte); + } + + // Make sure our Node and NodeList knows we've heard from this node. + Node* senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); + QUuid& nodeUUID = DEFAULT_NODE_ID_REF; + if (senderNode) { + senderNode->setLastHeardMicrostamp(usecTimestampNow()); + nodeUUID = senderNode->getUUID(); + if (debugProcessPacket) { + qDebug() << "sender has uuid=" << nodeUUID << "\n"; + } + } else { + if (debugProcessPacket) { + qDebug() << "sender has no known nodeUUID.\n"; + } + } + trackInboundPackets(nodeUUID, sequence, transitTime, editsInPacket, processTime, lockWaitTime); + } else { + printf("unknown packet ignored... packetData[0]=%c\n", packetData[0]); + } +} + +void OctreeInboundPacketProcessor::trackInboundPackets(const QUuid& nodeUUID, int sequence, uint64_t transitTime, + int editsInPacket, uint64_t processTime, uint64_t lockWaitTime) { + + _totalTransitTime += transitTime; + _totalProcessTime += processTime; + _totalLockWaitTime += lockWaitTime; + _totalElementsInPacket += editsInPacket; + _totalPackets++; + + // find the individual senders stats and track them there too... + // see if this is the first we've heard of this node... + if (_singleSenderStats.find(nodeUUID) == _singleSenderStats.end()) { + SingleSenderStats stats; + + stats._totalTransitTime += transitTime; + stats._totalProcessTime += processTime; + stats._totalLockWaitTime += lockWaitTime; + stats._totalElementsInPacket += editsInPacket; + stats._totalPackets++; + + _singleSenderStats[nodeUUID] = stats; + } else { + SingleSenderStats& stats = _singleSenderStats[nodeUUID]; + stats._totalTransitTime += transitTime; + stats._totalProcessTime += processTime; + stats._totalLockWaitTime += lockWaitTime; + stats._totalElementsInPacket += editsInPacket; + stats._totalPackets++; + } +} + + +SingleSenderStats::SingleSenderStats() { + _totalTransitTime = 0; + _totalProcessTime = 0; + _totalLockWaitTime = 0; + _totalElementsInPacket = 0; + _totalPackets = 0; +} + + diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h b/libraries/octree-server/src/OctreeInboundPacketProcessor.h similarity index 65% rename from libraries/voxel-server-library/src/VoxelServerPacketProcessor.h rename to libraries/octree-server/src/OctreeInboundPacketProcessor.h index 4abdbad284..51214b2617 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h +++ b/libraries/octree-server/src/OctreeInboundPacketProcessor.h @@ -1,5 +1,5 @@ // -// VoxelServerPacketProcessor.h +// OctreeInboundPacketProcessor.h // voxel-server // // Created by Brad Hefta-Gaub on 8/21/13 @@ -8,13 +8,13 @@ // Threaded or non-threaded network packet processor for the voxel-server // -#ifndef __voxel_server__VoxelServerPacketProcessor__ -#define __voxel_server__VoxelServerPacketProcessor__ +#ifndef __octree_server__OctreeInboundPacketProcessor__ +#define __octree_server__OctreeInboundPacketProcessor__ #include #include -class VoxelServer; +class OctreeServer; class SingleSenderStats { public: @@ -23,17 +23,17 @@ public: uint64_t getAverageTransitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalTransitTime / _totalPackets; } uint64_t getAverageProcessTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalProcessTime / _totalPackets; } uint64_t getAverageLockWaitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalLockWaitTime / _totalPackets; } - uint64_t getTotalVoxelsProcessed() const { return _totalVoxelsInPacket; } + uint64_t getTotalElementsProcessed() const { return _totalElementsInPacket; } uint64_t getTotalPacketsProcessed() const { return _totalPackets; } - uint64_t getAverageProcessTimePerVoxel() const - { return _totalVoxelsInPacket == 0 ? 0 : _totalProcessTime / _totalVoxelsInPacket; } - uint64_t getAverageLockWaitTimePerVoxel() const - { return _totalVoxelsInPacket == 0 ? 0 : _totalLockWaitTime / _totalVoxelsInPacket; } + uint64_t getAverageProcessTimePerElement() const + { return _totalElementsInPacket == 0 ? 0 : _totalProcessTime / _totalElementsInPacket; } + uint64_t getAverageLockWaitTimePerElement() const + { return _totalElementsInPacket == 0 ? 0 : _totalLockWaitTime / _totalElementsInPacket; } uint64_t _totalTransitTime; uint64_t _totalProcessTime; uint64_t _totalLockWaitTime; - uint64_t _totalVoxelsInPacket; + uint64_t _totalElementsInPacket; uint64_t _totalPackets; }; @@ -43,20 +43,20 @@ typedef std::map::iterator NodeToSenderStatsMapIterato /// Handles processing of incoming network packets for the voxel-server. As with other ReceivedPacketProcessor classes /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() -class VoxelServerPacketProcessor : public ReceivedPacketProcessor { +class OctreeInboundPacketProcessor : public ReceivedPacketProcessor { public: - VoxelServerPacketProcessor(VoxelServer* myServer); + OctreeInboundPacketProcessor(OctreeServer* myServer); uint64_t getAverageTransitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalTransitTime / _totalPackets; } uint64_t getAverageProcessTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalProcessTime / _totalPackets; } uint64_t getAverageLockWaitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalLockWaitTime / _totalPackets; } - uint64_t getTotalVoxelsProcessed() const { return _totalVoxelsInPacket; } + uint64_t getTotalElementsProcessed() const { return _totalElementsInPacket; } uint64_t getTotalPacketsProcessed() const { return _totalPackets; } - uint64_t getAverageProcessTimePerVoxel() const - { return _totalVoxelsInPacket == 0 ? 0 : _totalProcessTime / _totalVoxelsInPacket; } - uint64_t getAverageLockWaitTimePerVoxel() const - { return _totalVoxelsInPacket == 0 ? 0 : _totalLockWaitTime / _totalVoxelsInPacket; } + uint64_t getAverageProcessTimePerElement() const + { return _totalElementsInPacket == 0 ? 0 : _totalProcessTime / _totalElementsInPacket; } + uint64_t getAverageLockWaitTimePerElement() const + { return _totalElementsInPacket == 0 ? 0 : _totalLockWaitTime / _totalElementsInPacket; } void resetStats(); @@ -69,15 +69,15 @@ private: void trackInboundPackets(const QUuid& nodeUUID, int sequence, uint64_t transitTime, int voxelsInPacket, uint64_t processTime, uint64_t lockWaitTime); - VoxelServer* _myServer; + OctreeServer* _myServer; int _receivedPacketCount; uint64_t _totalTransitTime; uint64_t _totalProcessTime; uint64_t _totalLockWaitTime; - uint64_t _totalVoxelsInPacket; + uint64_t _totalElementsInPacket; uint64_t _totalPackets; NodeToSenderStatsMap _singleSenderStats; }; -#endif // __voxel_server__VoxelServerPacketProcessor__ +#endif // __octree_server__OctreeInboundPacketProcessor__ diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/octree-server/src/OctreePersistThread.cpp similarity index 80% rename from libraries/voxel-server-library/src/VoxelPersistThread.cpp rename to libraries/octree-server/src/OctreePersistThread.cpp index 6f0d8d6b1c..a3a2663342 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/octree-server/src/OctreePersistThread.cpp @@ -1,22 +1,21 @@ // -// VoxelPersistThread.cpp -// voxel-server +// OctreePersistThread.cpp +// Octree-server // // Created by Brad Hefta-Gaub on 8/21/13 // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -// Threaded or non-threaded voxel persistence +// Threaded or non-threaded Octree persistence // #include -#include #include #include -#include "VoxelPersistThread.h" -#include "VoxelServer.h" +#include "OctreePersistThread.h" +#include "OctreeServer.h" -VoxelPersistThread::VoxelPersistThread(VoxelTree* tree, const char* filename, int persistInterval) : +OctreePersistThread::OctreePersistThread(Octree* tree, const char* filename, int persistInterval) : _tree(tree), _filename(filename), _persistInterval(persistInterval), @@ -24,17 +23,17 @@ VoxelPersistThread::VoxelPersistThread(VoxelTree* tree, const char* filename, in _loadTimeUSecs(0) { } -bool VoxelPersistThread::process() { +bool OctreePersistThread::process() { if (!_initialLoadComplete) { uint64_t loadStarted = usecTimestampNow(); - qDebug("loading voxels from file: %s...\n", _filename); + qDebug("loading Octrees from file: %s...\n", _filename); bool persistantFileRead; _tree->lockForWrite(); { - PerformanceWarning warn(true, "Loading Voxel File", true); + PerformanceWarning warn(true, "Loading Octree File", true); persistantFileRead = _tree->readFromSVOFile(_filename); } _tree->unlock(); @@ -44,7 +43,7 @@ bool VoxelPersistThread::process() { _loadTimeUSecs = loadDone - loadStarted; _tree->clearDirtyBit(); // the tree is clean since we just loaded it - qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); + qDebug("DONE loading Octrees from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); unsigned long nodeCount = OctreeElement::getNodeCount(); unsigned long internalNodeCount = OctreeElement::getInternalNodeCount(); @@ -75,10 +74,10 @@ bool VoxelPersistThread::process() { // check the dirty bit and persist here... _lastCheck = usecTimestampNow(); if (_tree->isDirty()) { - qDebug("saving voxels to file %s...\n",_filename); + qDebug("saving Octrees to file %s...\n",_filename); _tree->writeToSVOFile(_filename); _tree->clearDirtyBit(); // tree is clean after saving - qDebug("DONE saving voxels to file...\n"); + qDebug("DONE saving Octrees to file...\n"); } } } diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.h b/libraries/octree-server/src/OctreePersistThread.h similarity index 63% rename from libraries/voxel-server-library/src/VoxelPersistThread.h rename to libraries/octree-server/src/OctreePersistThread.h index de6b4ab094..e5f261960b 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.h +++ b/libraries/octree-server/src/OctreePersistThread.h @@ -1,26 +1,25 @@ // -// VoxelPersistThread.h -// voxel-server +// OctreePersistThread.h +// Octree-server // // Created by Brad Hefta-Gaub on 8/21/13 // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -// Threaded or non-threaded voxel persistence +// Threaded or non-threaded Octree persistence // -#ifndef __voxel_server__VoxelPersistThread__ -#define __voxel_server__VoxelPersistThread__ +#ifndef __Octree_server__OctreePersistThread__ +#define __Octree_server__OctreePersistThread__ #include -#include -#include +#include /// Generalized threaded processor for handling received inbound packets. -class VoxelPersistThread : public virtual GenericThread { +class OctreePersistThread : public virtual GenericThread { public: static const int DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds - VoxelPersistThread(VoxelTree* tree, const char* filename, int persistInterval = DEFAULT_PERSIST_INTERVAL); + OctreePersistThread(Octree* tree, const char* filename, int persistInterval = DEFAULT_PERSIST_INTERVAL); bool isInitialLoadComplete() const { return _initialLoadComplete; } @@ -31,7 +30,7 @@ protected: /// Implements generic processing behavior for this thread. virtual bool process(); private: - VoxelTree* _tree; + Octree* _tree; const char* _filename; int _persistInterval; bool _initialLoadComplete; @@ -41,4 +40,4 @@ private: uint64_t _lastCheck; }; -#endif // __voxel_server__VoxelPersistThread__ +#endif // __Octree_server__OctreePersistThread__ diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/octree-server/src/OctreeQueryNode.cpp similarity index 65% rename from libraries/voxel-server-library/src/VoxelNodeData.cpp rename to libraries/octree-server/src/OctreeQueryNode.cpp index a4c4bfebe2..0e84fe2dba 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/octree-server/src/OctreeQueryNode.cpp @@ -1,5 +1,5 @@ // -// VoxelNodeData.cpp +// OctreeQueryNode.cpp // hifi // // Created by Stephen Birarda on 3/21/13. @@ -8,15 +8,15 @@ #include "PacketHeaders.h" #include "SharedUtil.h" -#include "VoxelNodeData.h" +#include "OctreeQueryNode.h" #include #include -#include "VoxelSendThread.h" +#include "OctreeSendThread.h" -VoxelNodeData::VoxelNodeData(Node* owningNode) : - VoxelQuery(owningNode), +OctreeQueryNode::OctreeQueryNode(Node* owningNode) : + OctreeQuery(owningNode), _viewSent(false), - _voxelPacketAvailableBytes(MAX_PACKET_SIZE), + _octreePacketAvailableBytes(MAX_PACKET_SIZE), _maxSearchLevel(1), _maxLevelReachedInLastSearch(1), _lastTimeBagEmpty(0), @@ -24,39 +24,38 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _viewFrustumJustStoppedChanging(true), _currentPacketIsColor(true), _currentPacketIsCompressed(false), - _voxelSendThread(NULL), + _octreeSendThread(NULL), _lastClientBoundaryLevelAdjust(0), - _lastClientVoxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), + _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _lodChanged(false), _lodInitialized(false) { - _voxelPacket = new unsigned char[MAX_PACKET_SIZE]; - _voxelPacketAt = _voxelPacket; - _lastVoxelPacket = new unsigned char[MAX_PACKET_SIZE]; - _lastVoxelPacketLength = 0; + _octreePacket = new unsigned char[MAX_PACKET_SIZE]; + _octreePacketAt = _octreePacket; + _lastOctreePacket = new unsigned char[MAX_PACKET_SIZE]; + _lastOctreePacketLength = 0; _duplicatePacketCount = 0; _sequenceNumber = 0; - resetVoxelPacket(true); // don't bump sequence } -void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { - // Create voxel sending thread... +void OctreeQueryNode::initializeOctreeSendThread(OctreeServer* octreeServer) { + // Create octree sending thread... QUuid nodeUUID = getOwningNode()->getUUID(); - _voxelSendThread = new VoxelSendThread(nodeUUID, voxelServer); - _voxelSendThread->initialize(true); + _octreeSendThread = new OctreeSendThread(nodeUUID, octreeServer); + _octreeSendThread->initialize(true); } -bool VoxelNodeData::packetIsDuplicate() const { +bool OctreeQueryNode::packetIsDuplicate() const { // since our packets now include header information, like sequence number, and createTime, we can't just do a memcmp // of the entire packet, we need to compare only the packet content... - if (_lastVoxelPacketLength == getPacketLength()) { - return memcmp(_lastVoxelPacket + VOXEL_PACKET_HEADER_SIZE, - _voxelPacket+VOXEL_PACKET_HEADER_SIZE , getPacketLength() - VOXEL_PACKET_HEADER_SIZE) == 0; + if (_lastOctreePacketLength == getPacketLength()) { + return memcmp(_lastOctreePacket + OCTREE_PACKET_HEADER_SIZE, + _octreePacket+OCTREE_PACKET_HEADER_SIZE , getPacketLength() - OCTREE_PACKET_HEADER_SIZE == 0); } return false; } -bool VoxelNodeData::shouldSuppressDuplicatePacket() { +bool OctreeQueryNode::shouldSuppressDuplicatePacket() { bool shouldSuppress = false; // assume we won't suppress // only consider duplicate packets @@ -90,19 +89,19 @@ bool VoxelNodeData::shouldSuppressDuplicatePacket() { return shouldSuppress; } -void VoxelNodeData::resetVoxelPacket(bool lastWasSurpressed) { +void OctreeQueryNode::resetOctreePacket(bool lastWasSurpressed) { // Whenever we call this, we will keep a copy of the last packet, so we can determine if the last packet has // changed since we last reset it. Since we know that no two packets can ever be identical without being the same // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing // packet send rate. - _lastVoxelPacketLength = getPacketLength(); - memcpy(_lastVoxelPacket, _voxelPacket, _lastVoxelPacketLength); + _lastOctreePacketLength = getPacketLength(); + memcpy(_lastOctreePacket, _octreePacket, _lastOctreePacketLength); // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. _currentPacketIsColor = getWantColor(); _currentPacketIsCompressed = getWantCompression(); - VOXEL_PACKET_FLAGS flags = 0; + OCTREE_PACKET_FLAGS flags = 0; if (_currentPacketIsColor) { setAtBit(flags,PACKET_IS_COLOR_BIT); } @@ -110,63 +109,63 @@ void VoxelNodeData::resetVoxelPacket(bool lastWasSurpressed) { setAtBit(flags,PACKET_IS_COMPRESSED_BIT); } - _voxelPacketAvailableBytes = MAX_PACKET_SIZE; - int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, PACKET_TYPE_VOXEL_DATA); - _voxelPacketAt = _voxelPacket + numBytesPacketHeader; - _voxelPacketAvailableBytes -= numBytesPacketHeader; + _octreePacketAvailableBytes = MAX_PACKET_SIZE; + int numBytesPacketHeader = populateTypeAndVersion(_octreePacket, getMyPacketType()); + _octreePacketAt = _octreePacket + numBytesPacketHeader; + _octreePacketAvailableBytes -= numBytesPacketHeader; // pack in flags - VOXEL_PACKET_FLAGS* flagsAt = (VOXEL_PACKET_FLAGS*)_voxelPacketAt; + OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)_octreePacketAt; *flagsAt = flags; - _voxelPacketAt += sizeof(VOXEL_PACKET_FLAGS); - _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_FLAGS); + _octreePacketAt += sizeof(OCTREE_PACKET_FLAGS); + _octreePacketAvailableBytes -= sizeof(OCTREE_PACKET_FLAGS); // pack in sequence number - VOXEL_PACKET_SEQUENCE* sequenceAt = (VOXEL_PACKET_SEQUENCE*)_voxelPacketAt; + OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)_octreePacketAt; *sequenceAt = _sequenceNumber; - _voxelPacketAt += sizeof(VOXEL_PACKET_SEQUENCE); - _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_SEQUENCE); - if (!(lastWasSurpressed || _lastVoxelPacketLength == VOXEL_PACKET_HEADER_SIZE)) { + _octreePacketAt += sizeof(OCTREE_PACKET_SEQUENCE); + _octreePacketAvailableBytes -= sizeof(OCTREE_PACKET_SEQUENCE); + if (!(lastWasSurpressed || _lastOctreePacketLength == OCTREE_PACKET_HEADER_SIZE)) { _sequenceNumber++; } // pack in timestamp - VOXEL_PACKET_SENT_TIME now = usecTimestampNow(); - VOXEL_PACKET_SENT_TIME* timeAt = (VOXEL_PACKET_SENT_TIME*)_voxelPacketAt; + OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); + OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)_octreePacketAt; *timeAt = now; - _voxelPacketAt += sizeof(VOXEL_PACKET_SENT_TIME); - _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_SENT_TIME); + _octreePacketAt += sizeof(OCTREE_PACKET_SENT_TIME); + _octreePacketAvailableBytes -= sizeof(OCTREE_PACKET_SENT_TIME); - _voxelPacketWaiting = false; + _octreePacketWaiting = false; } -void VoxelNodeData::writeToPacket(const unsigned char* buffer, int bytes) { +void OctreeQueryNode::writeToPacket(const unsigned char* buffer, int bytes) { // compressed packets include lead bytes which contain compressed size, this allows packing of // multiple compressed portions together if (_currentPacketIsCompressed) { - *(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)_voxelPacketAt = bytes; - _voxelPacketAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); - _voxelPacketAvailableBytes -= sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + *(OCTREE_PACKET_INTERNAL_SECTION_SIZE*)_octreePacketAt = bytes; + _octreePacketAt += sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + _octreePacketAvailableBytes -= sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } - if (bytes <= _voxelPacketAvailableBytes) { - memcpy(_voxelPacketAt, buffer, bytes); - _voxelPacketAvailableBytes -= bytes; - _voxelPacketAt += bytes; - _voxelPacketWaiting = true; + if (bytes <= _octreePacketAvailableBytes) { + memcpy(_octreePacketAt, buffer, bytes); + _octreePacketAvailableBytes -= bytes; + _octreePacketAt += bytes; + _octreePacketWaiting = true; } } -VoxelNodeData::~VoxelNodeData() { - delete[] _voxelPacket; - delete[] _lastVoxelPacket; +OctreeQueryNode::~OctreeQueryNode() { + delete[] _octreePacket; + delete[] _lastOctreePacket; - if (_voxelSendThread) { - _voxelSendThread->terminate(); - delete _voxelSendThread; + if (_octreeSendThread) { + _octreeSendThread->terminate(); + delete _octreeSendThread; } } -bool VoxelNodeData::updateCurrentViewFrustum() { +bool OctreeQueryNode::updateCurrentViewFrustum() { bool currentViewFrustumChanged = false; ViewFrustum newestViewFrustum; // get position and orientation details from the camera @@ -196,13 +195,13 @@ bool VoxelNodeData::updateCurrentViewFrustum() { _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); _lodChanged = true; } - if (_lastClientVoxelSizeScale != getOctreeSizeScale()) { - _lastClientVoxelSizeScale = getOctreeSizeScale(); + if (_lastClientOctreeSizeScale != getOctreeSizeScale()) { + _lastClientOctreeSizeScale = getOctreeSizeScale(); _lodChanged = true; } } else { _lodInitialized = true; - _lastClientVoxelSizeScale = getOctreeSizeScale(); + _lastClientOctreeSizeScale = getOctreeSizeScale(); _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); _lodChanged = false; } @@ -217,7 +216,7 @@ bool VoxelNodeData::updateCurrentViewFrustum() { return currentViewFrustumChanged; } -void VoxelNodeData::setViewSent(bool viewSent) { +void OctreeQueryNode::setViewSent(bool viewSent) { _viewSent = viewSent; if (viewSent) { _viewFrustumJustStoppedChanging = false; @@ -225,7 +224,7 @@ void VoxelNodeData::setViewSent(bool viewSent) { } } -void VoxelNodeData::updateLastKnownViewFrustum() { +void OctreeQueryNode::updateLastKnownViewFrustum() { bool frustumChanges = !_lastKnownViewFrustum.isVerySimilar(_currentViewFrustum); if (frustumChanges) { @@ -239,7 +238,7 @@ void VoxelNodeData::updateLastKnownViewFrustum() { } -bool VoxelNodeData::moveShouldDump() const { +bool OctreeQueryNode::moveShouldDump() const { glm::vec3 oldPosition = _lastKnownViewFrustum.getPosition(); glm::vec3 newPosition = _currentViewFrustum.getPosition(); @@ -251,7 +250,7 @@ bool VoxelNodeData::moveShouldDump() const { return false; } -void VoxelNodeData::dumpOutOfView() { +void OctreeQueryNode::dumpOutOfView() { int stillInView = 0; int outOfView = 0; OctreeElementBag tempBag; diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/octree-server/src/OctreeQueryNode.h similarity index 62% rename from libraries/voxel-server-library/src/VoxelNodeData.h rename to libraries/octree-server/src/OctreeQueryNode.h index 7a39fb4362..865f1607ab 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/octree-server/src/OctreeQueryNode.h @@ -1,44 +1,46 @@ // -// VoxelNodeData.h +// OctreeQueryNode.h // hifi // -// Created by Stephen Birarda on 3/21/13. +// Created by Brad Hefta-Gaub on 12/4/13. // // -#ifndef __hifi__VoxelNodeData__ -#define __hifi__VoxelNodeData__ +#ifndef __hifi__OctreeQueryNode__ +#define __hifi__OctreeQueryNode__ #include #include -#include -#include +#include +#include #include -#include +#include #include -#include +#include -class VoxelSendThread; -class VoxelServer; +class OctreeSendThread; +class OctreeServer; -class VoxelNodeData : public VoxelQuery { +class OctreeQueryNode : public OctreeQuery { public: - VoxelNodeData(Node* owningNode); - virtual ~VoxelNodeData(); + OctreeQueryNode(Node* owningNode); + virtual ~OctreeQueryNode(); + + virtual PACKET_TYPE getMyPacketType() const = 0; - void resetVoxelPacket(bool lastWasSurpressed = false); // resets voxel packet to after "V" header + void resetOctreePacket(bool lastWasSurpressed = false); // resets octree packet to after "V" header void writeToPacket(const unsigned char* buffer, int bytes); // writes to end of packet - const unsigned char* getPacket() const { return _voxelPacket; } - int getPacketLength() const { return (MAX_PACKET_SIZE - _voxelPacketAvailableBytes); } - bool isPacketWaiting() const { return _voxelPacketWaiting; } + const unsigned char* getPacket() const { return _octreePacket; } + int getPacketLength() const { return (MAX_PACKET_SIZE - _octreePacketAvailableBytes); } + bool isPacketWaiting() const { return _octreePacketWaiting; } bool packetIsDuplicate() const; bool shouldSuppressDuplicatePacket(); - int getAvailable() const { return _voxelPacketAvailableBytes; } + int getAvailable() const { return _octreePacketAvailableBytes; } int getMaxSearchLevel() const { return _maxSearchLevel; } void resetMaxSearchLevel() { _maxSearchLevel = 1; } void incrementMaxSearchLevel() { _maxSearchLevel++; } @@ -76,25 +78,25 @@ public: bool hasLodChanged() const { return _lodChanged; }; - VoxelSceneStats stats; + OctreeSceneStats stats; - void initializeVoxelSendThread(VoxelServer* voxelServer); - bool isVoxelSendThreadInitalized() { return _voxelSendThread; } + void initializeOctreeSendThread(OctreeServer* octreeServer); + bool isOctreeSendThreadInitalized() { return _octreeSendThread; } void dumpOutOfView(); private: - VoxelNodeData(const VoxelNodeData &); - VoxelNodeData& operator= (const VoxelNodeData&); + OctreeQueryNode(const OctreeQueryNode &); + OctreeQueryNode& operator= (const OctreeQueryNode&); bool _viewSent; - unsigned char* _voxelPacket; - unsigned char* _voxelPacketAt; - int _voxelPacketAvailableBytes; - bool _voxelPacketWaiting; + unsigned char* _octreePacket; + unsigned char* _octreePacketAt; + int _octreePacketAvailableBytes; + bool _octreePacketWaiting; - unsigned char* _lastVoxelPacket; - int _lastVoxelPacketLength; + unsigned char* _lastOctreePacket; + int _lastOctreePacketLength; int _duplicatePacketCount; uint64_t _firstSuppressedPacket; @@ -108,15 +110,15 @@ private: bool _currentPacketIsColor; bool _currentPacketIsCompressed; - VoxelSendThread* _voxelSendThread; + OctreeSendThread* _octreeSendThread; // watch for LOD changes int _lastClientBoundaryLevelAdjust; - float _lastClientVoxelSizeScale; + float _lastClientOctreeSizeScale; bool _lodChanged; bool _lodInitialized; - VOXEL_PACKET_SEQUENCE _sequenceNumber; + OCTREE_PACKET_SEQUENCE _sequenceNumber; }; -#endif /* defined(__hifi__VoxelNodeData__) */ +#endif /* defined(__hifi__OctreeQueryNode__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/octree-server/src/OctreeSendThread.cpp similarity index 83% rename from libraries/voxel-server-library/src/VoxelSendThread.cpp rename to libraries/octree-server/src/OctreeSendThread.cpp index 669979e0b0..eb53f5a3ad 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/octree-server/src/OctreeSendThread.cpp @@ -1,43 +1,34 @@ // -// VoxelSendThread.cpp -// voxel-server +// OctreeSendThread.cpp // // Created by Brad Hefta-Gaub on 8/21/13 // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -// Threaded or non-threaded voxel packet sender -// -#include #include #include #include #include -extern EnvironmentData environmentData[3]; - - -#include "VoxelSendThread.h" -#include "VoxelServer.h" -#include "VoxelServerConsts.h" - +#include "OctreeSendThread.h" +#include "OctreeServer.h" +#include "OctreeServerConsts.h" uint64_t startSceneSleepTime = 0; uint64_t endSceneSleepTime = 0; - -VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) : +OctreeSendThread::OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer) : _nodeUUID(nodeUUID), _myServer(myServer), _packetData() { } -bool VoxelSendThread::process() { +bool OctreeSendThread::process() { uint64_t start = usecTimestampNow(); bool gotLock = false; - // don't do any send processing until the initial load of the voxels is complete... + // don't do any send processing until the initial load of the octree is complete... if (_myServer->isInitialLoadComplete()) { Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); @@ -45,41 +36,41 @@ bool VoxelSendThread::process() { // make sure the node list doesn't kill our node while we're using it if (node->trylock()) { gotLock = true; - VoxelNodeData* nodeData = NULL; + OctreeQueryNode* nodeData = NULL; - nodeData = (VoxelNodeData*) node->getLinkedData(); + nodeData = (OctreeQueryNode*) node->getLinkedData(); int packetsSent = 0; // Sometimes the node data has not yet been linked, in which case we can't really do anything if (nodeData) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); } - packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged); + packetsSent = packetDistributor(node, nodeData, viewFrustumChanged); } node->unlock(); // we're done with this node for now. } } } else { - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - qDebug("VoxelSendThread::process() waiting for isInitialLoadComplete()\n"); + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { + qDebug("OctreeSendThread::process() waiting for isInitialLoadComplete()\n"); } } // Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap if (isStillRunning() && gotLock) { - // dynamically sleep until we need to fire off the next set of voxels + // dynamically sleep until we need to fire off the next set of octree elements int elapsed = (usecTimestampNow() - start); - int usecToSleep = VOXEL_SEND_INTERVAL_USECS - elapsed; + int usecToSleep = OCTREE_SEND_INTERVAL_USECS - elapsed; if (usecToSleep > 0) { - PerformanceWarning warn(false,"VoxelSendThread... usleep()",false,&_usleepTime,&_usleepCalls); + PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { std::cout << "Last send took too much time, not sleeping!\n"; } } @@ -88,15 +79,15 @@ bool VoxelSendThread::process() { return isStillRunning(); // keep running till they terminate us } -uint64_t VoxelSendThread::_usleepTime = 0; -uint64_t VoxelSendThread::_usleepCalls = 0; +uint64_t OctreeSendThread::_usleepTime = 0; +uint64_t OctreeSendThread::_usleepCalls = 0; -uint64_t VoxelSendThread::_totalBytes = 0; -uint64_t VoxelSendThread::_totalWastedBytes = 0; -uint64_t VoxelSendThread::_totalPackets = 0; +uint64_t OctreeSendThread::_totalBytes = 0; +uint64_t OctreeSendThread::_totalWastedBytes = 0; +uint64_t OctreeSendThread::_totalPackets = 0; -int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { - bool debug = _myServer->wantsDebugVoxelSending(); +int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent) { + bool debug = _myServer->wantsDebugSending(); uint64_t now = usecTimestampNow(); bool packetSent = false; // did we send a packet? @@ -105,16 +96,16 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about // this rate control savings. if (nodeData->shouldSuppressDuplicatePacket()) { - nodeData->resetVoxelPacket(true); // we still need to reset it though! + nodeData->resetOctreePacket(true); // we still need to reset it though! return packetsSent; // without sending... } const unsigned char* messageData = nodeData->getPacket(); int numBytesPacketHeader = numBytesForPacketHeader(messageData); const unsigned char* dataAt = messageData + numBytesPacketHeader; - dataAt += sizeof(VOXEL_PACKET_FLAGS); - VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); - dataAt += sizeof(VOXEL_PACKET_SEQUENCE); + dataAt += sizeof(OCTREE_PACKET_FLAGS); + OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); // If we've got a stats message ready to send, then see if we can piggyback them together @@ -220,14 +211,14 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent += nodeData->getPacketLength(); truePacketsSent++; packetsSent++; - nodeData->resetVoxelPacket(); + nodeData->resetOctreePacket(); } return packetsSent; } /// Version of voxel distributor that sends the deepest LOD level at once -int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) { +int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, bool viewFrustumChanged) { int truePacketsSent = 0; int trueBytesSent = 0; @@ -248,7 +239,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // then let's just send that waiting packet. if (!nodeData->getCurrentPacketFormatMatches()) { if (nodeData->isPacketWaiting()) { - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s currentPacketIsCompressed=%s\n", debug::valueOf(wantColor), debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsColor()), @@ -256,19 +247,19 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } else { - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s\n", debug::valueOf(wantColor), debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsColor()), debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); } - nodeData->resetVoxelPacket(); + nodeData->resetOctreePacket(); } - int targetSize = MAX_VOXEL_PACKET_DATA_SIZE; + int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__, debug::valueOf(wantCompression), targetSize); } @@ -276,7 +267,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod _packetData.changeSettings(wantCompression, targetSize); } - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s\n", debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()), @@ -285,8 +276,8 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { - printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n", + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { + printf("packetDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n", debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()), debug::valueOf(nodeData->getViewSent()) ); @@ -296,7 +287,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // the current view frustum for things to send. if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { uint64_t now = usecTimestampNow(); - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n", debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty())); if (nodeData->getLastTimeBagEmpty() > 0) { @@ -314,7 +305,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // if our view has changed, we need to reset these things... if (viewFrustumChanged) { - if (_myServer->wantDumpVoxelsOnMove() || nodeData->moveShouldDump() || nodeData->hasLodChanged()) { + if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) { nodeData->dumpOutOfView(); } nodeData->map.erase(); @@ -335,15 +326,11 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod unsigned long elapsedTime = nodeData->stats.getElapsedTime(); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugSending()) { qDebug("Scene completed at %llu encodeTime:%lu sleepTime:%lu elapsed:%lu Packets:%llu Bytes:%llu Wasted:%llu\n", usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); } - if (_myServer->wantDisplayVoxelStats()) { - nodeData->stats.printDebugDetails(); - } - // start tracking our stats bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); @@ -353,22 +340,22 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->nodeBag.deleteAll(); } - if (_myServer->wantsDebugVoxelSending()) { + if (_myServer->wantsDebugSending()) { qDebug("Scene started at %llu Packets:%llu Bytes:%llu Wasted:%llu\n", usecTimestampNow(),_totalPackets,_totalBytes,_totalWastedBytes); } ::startSceneSleepTime = _usleepTime; - nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().getRoot(), _myServer->getJurisdiction()); + nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot(), _myServer->getJurisdiction()); // This is the start of "resending" the scene. bool dontRestartSceneOnMove = false; // this is experimental if (dontRestartSceneOnMove) { if (nodeData->nodeBag.isEmpty()) { - nodeData->nodeBag.insert(_myServer->getServerTree().getRoot()); // only in case of empty + nodeData->nodeBag.insert(_myServer->getOctree()->getRoot()); // only in case of empty } } else { - nodeData->nodeBag.insert(_myServer->getServerTree().getRoot()); // original behavior, reset on move or empty + nodeData->nodeBag.insert(_myServer->getOctree()->getRoot()); // original behavior, reset on move or empty } } @@ -376,23 +363,21 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (!nodeData->nodeBag.isEmpty()) { int bytesWritten = 0; uint64_t start = usecTimestampNow(); - uint64_t startCompressTimeMsecs = VoxelPacketData::getCompressContentTime() / 1000; - uint64_t startCompressCalls = VoxelPacketData::getCompressContentCalls(); - - bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); + uint64_t startCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; + uint64_t startCompressCalls = OctreePacketData::getCompressContentCalls(); int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND)); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval); } int extraPackingAttempts = 0; - while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) { - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval); @@ -421,12 +406,12 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod isFullScene, &nodeData->stats, _myServer->getJurisdiction()); - _myServer->getServerTree().lockForRead(); + _myServer->getOctree()->lockForRead(); nodeData->stats.encodeStarted(); - bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); + bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); // if we're trying to fill a full size packet, then we use this logic to determine if we have a DIDNT_FIT case. - if (_packetData.getTargetSize() == MAX_VOXEL_PACKET_DATA_SIZE) { + if (_packetData.getTargetSize() == MAX_OCTREE_PACKET_DATA_SIZE) { if (_packetData.hasContent() && bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { lastNodeDidntFit = true; @@ -442,7 +427,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } nodeData->stats.encodeStopped(); - _myServer->getServerTree().unlock(); + _myServer->getOctree()->unlock(); } else { // If the bag was empty then we didn't even attempt to encode, and so we know the bytesWritten were 0 bytesWritten = 0; @@ -461,18 +446,18 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // form actually inflated beyond our padding, and in this case we will send the current packet, then // write to out new packet... int writtenSize = _packetData.getFinalizedSize() - + (nodeData->getCurrentPacketIsCompressed() ? sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE) : 0); + + (nodeData->getCurrentPacketIsCompressed() ? sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) : 0); if (writtenSize > nodeData->getAvailable()) { - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("writtenSize[%d] > available[%d] too big, sending packet as is.\n", writtenSize, nodeData->getAvailable()); } packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%d\n", nodeData->getAvailable(), _packetData.getFinalizedSize(), _packetData.getUncompressedSize(), _packetData.getTargetSize()); @@ -491,11 +476,11 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod sendNow = false; // try to pack more } - int targetSize = MAX_VOXEL_PACKET_DATA_SIZE; + int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; if (sendNow) { packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } } else { // If we're in compressed mode, then we want to see if we have room for more in this wire packet. @@ -504,9 +489,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod // in the wire packet. We also include room for our section header, and a little bit of padding // to account for the fact that whenc compressing small amounts of data, we sometimes end up with // a larger compressed size then uncompressed size - targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; } - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__, debug::valueOf(nodeData->getWantCompression()), targetSize); } @@ -514,8 +499,15 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } } + + // Here's where we can/should allow the server to send other data... // send the environment packet - if (shouldSendEnvironments) { + if (_myServer->hasSpecialPacketToSend()) { + trueBytesSent += _myServer->sendSpecialPacket(node); + truePacketsSent++; + packetsSentThisInterval++; + + /** int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA); int envPacketLength = numBytesPacketHeader; int environmentsToSend = _myServer->getSendMinimalEnvironment() ? 1 : _myServer->getEnvironmentDataCount(); @@ -530,15 +522,17 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod trueBytesSent += envPacketLength; truePacketsSent++; packetsSentThisInterval++; + **/ } + uint64_t end = usecTimestampNow(); int elapsedmsec = (end - start)/1000; - uint64_t endCompressCalls = VoxelPacketData::getCompressContentCalls(); + uint64_t endCompressCalls = OctreePacketData::getCompressContentCalls(); int elapsedCompressCalls = endCompressCalls - startCompressCalls; - uint64_t endCompressTimeMsecs = VoxelPacketData::getCompressContentTime() / 1000; + uint64_t endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; @@ -551,7 +545,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod printf("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } - } else if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + } else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } @@ -561,13 +555,13 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod if (nodeData->nodeBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { nodeData->map.printStats(); } nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } - if (_myServer->wantsDebugVoxelSending() && _myServer->wantsVerboseDebug()) { + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval); diff --git a/libraries/octree-server/src/OctreeSendThread.h b/libraries/octree-server/src/OctreeSendThread.h new file mode 100644 index 0000000000..a2de8fcb5d --- /dev/null +++ b/libraries/octree-server/src/OctreeSendThread.h @@ -0,0 +1,45 @@ +// +// OctreeSendThread.h +// +// Created by Brad Hefta-Gaub on 8/21/13 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// Threaded or non-threaded object for sending voxels to a client +// + +#ifndef __octree_server__OctreeSendThread__ +#define __octree_server__OctreeSendThread__ + +#include +#include +#include +#include "OctreeQueryNode.h" +#include "OctreeServer.h" + +/// Threaded processor for sending voxel packets to a single client +class OctreeSendThread : public virtual GenericThread { +public: + OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer); + + static uint64_t _totalBytes; + static uint64_t _totalWastedBytes; + static uint64_t _totalPackets; + + static uint64_t _usleepTime; + static uint64_t _usleepCalls; + +protected: + /// Implements generic processing behavior for this thread. + virtual bool process(); + +private: + QUuid _nodeUUID; + OctreeServer* _myServer; + + int handlePacketSend(Node* node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); + int packetDistributor(Node* node, OctreeQueryNode* nodeData, bool viewFrustumChanged); + + OctreePacketData _packetData; +}; + +#endif // __octree_server__OctreeSendThread__ diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/octree-server/src/OctreeServer.cpp similarity index 66% rename from libraries/voxel-server-library/src/VoxelServer.cpp rename to libraries/octree-server/src/OctreeServer.cpp index 96323f7d1a..8a8766851d 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -1,81 +1,65 @@ // -// VoxelServer.cpp +// OctreeServer.cpp // hifi // // Created by Brad Hefta-Gaub on 9/16/13. // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // -#include -#include -#include -#include -#include - -#include -#include #include #include #include -#include -#include -#include -#include -#include "VoxelNodeData.h" -#include -#include -#include -#include -#include #include -#ifdef _WIN32 -#include "Syssocket.h" -#include "Systime.h" -#else -#include -#include -#include -#endif +#include "civetweb.h" -#include "VoxelServer.h" -#include "VoxelServerConsts.h" +#include "OctreeServer.h" +#include "OctreeServerConsts.h" -const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo"; -const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo"; - -void attachVoxelNodeDataToNode(Node* newNode) { +void OctreeServer::attachQueryNodeToNode(Node* newNode) { if (newNode->getLinkedData() == NULL) { - VoxelNodeData* voxelNodeData = new VoxelNodeData(newNode); - newNode->setLinkedData(voxelNodeData); + if (GetInstance()) { + OctreeQueryNode* newQueryNodeData = GetInstance()->createOctreeQueryNode(newNode); + newQueryNodeData->resetOctreePacket(true); // don't bump sequence + newNode->setLinkedData(newQueryNodeData); + } } } -VoxelServer* VoxelServer::_theInstance = NULL; +void OctreeServer::nodeAdded(Node* node) { + // do nothing +} -VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : - ThreadedAssignment(dataBuffer, numBytes), - _serverTree(true) +void OctreeServer::nodeKilled(Node* node) { + // Use this to cleanup our node + if (node->getType() == NODE_TYPE_AGENT) { + OctreeQueryNode* nodeData = (OctreeQueryNode*)node->getLinkedData(); + if (nodeData) { + node->setLinkedData(NULL); + delete nodeData; + } + } +}; + + +OctreeServer* OctreeServer::_theInstance = NULL; + +OctreeServer::OctreeServer(const unsigned char* dataBuffer, int numBytes) : + ThreadedAssignment(dataBuffer, numBytes) { _argc = 0; _argv = NULL; - + _tree = NULL; _packetsPerClientPerInterval = 10; - _wantVoxelPersist = true; - _wantLocalDomain = false; - _debugVoxelSending = false; - _shouldShowAnimationDebug = false; - _displayVoxelStats = false; - _debugVoxelReceiving = false; - _sendEnvironments = true; - _sendMinimalEnvironment = false; - _dumpVoxelsOnMove = false; + _wantPersist = true; + _debugSending = false; + _debugReceiving = false; _verboseDebug = false; _jurisdiction = NULL; _jurisdictionSender = NULL; - _voxelServerPacketProcessor = NULL; - _voxelPersistThread = NULL; + _octreeInboundPacketProcessor = NULL; + _persistThread = NULL; _parsedArgV = NULL; _started = time(0); @@ -84,7 +68,7 @@ VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : _theInstance = this; } -VoxelServer::~VoxelServer() { +OctreeServer::~OctreeServer() { if (_parsedArgV) { for (int i = 0; i < _argc; i++) { delete[] _parsedArgV[i]; @@ -93,7 +77,7 @@ VoxelServer::~VoxelServer() { } } -void VoxelServer::initMongoose(int port) { +void OctreeServer::initMongoose(int port) { // setup the mongoose web server struct mg_callbacks callbacks = {}; @@ -113,10 +97,10 @@ void VoxelServer::initMongoose(int port) { mg_start(&callbacks, NULL, options); } -int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { +int OctreeServer::civetwebRequestHandler(struct mg_connection* connection) { const struct mg_request_info* ri = mg_get_request_info(connection); - VoxelServer* theServer = GetInstance(); + OctreeServer* theServer = GetInstance(); #ifdef FORCE_CRASH if (strcmp(ri->uri, "/force_crash") == 0 && strcmp(ri->request_method, "GET") == 0) { @@ -137,7 +121,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { } if (strcmp(ri->uri, "/resetStats") == 0 && strcmp(ri->request_method, "GET") == 0) { - theServer->_voxelServerPacketProcessor->resetStats(); + theServer->_octreeInboundPacketProcessor->resetStats(); showStats = true; } @@ -148,7 +132,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "Content-Type: text/html\r\n\r\n"); mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "
\r\n");
-        mg_printf(connection, "%s", "Your Voxel Server is running... [RELOAD]\r\n");
+        mg_printf(connection, "Your %s Server is running... [RELOAD]\r\n", theServer->getMyServerName());
 
         tm* localtm = localtime(&theServer->_started);
         const int MAX_TIME_LENGTH = 128;
@@ -198,7 +182,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
                 const int MAX_TIME_LENGTH = 128;
                 char buffer[MAX_TIME_LENGTH];
                 strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", voxelsLoadedAtLocal);
-                mg_printf(connection, "Voxels Loaded At: %s", buffer);
+                mg_printf(connection, "%s File Loaded At: %s", theServer->getMyServerName(), buffer);
 
                 // Convert now to tm struct for UTC
                 tm* voxelsLoadedAtUTM = gmtime(theServer->getLoadCompleted());
@@ -207,7 +191,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
                     mg_printf(connection, " [%s UTM] ", buffer);
                 }
             } else {
-                mg_printf(connection, "%s", "Voxel Persist Disabled...\r\n");
+                mg_printf(connection, "%s File Persist Disabled...\r\n", theServer->getMyServerName());
             }
             mg_printf(connection, "%s", "\r\n");
 
@@ -217,7 +201,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
             int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
             int hours = (msecsElapsed/(MSECS_PER_MIN * MIN_PER_HOUR));
 
-            mg_printf(connection, "%s", "Voxels Load Took: ");
+            mg_printf(connection, "%s File Load Took: ", theServer->getMyServerName());
             if (hours > 0) {
                 mg_printf(connection, "%d hour%s ", hours, (hours > 1) ? "s" : "" );
             }
@@ -267,13 +251,13 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
 
 
         // display outbound packet stats
-        mg_printf(connection, "%s", "Voxel Packet Statistics...\r\n");
-        uint64_t totalOutboundPackets = VoxelSendThread::_totalPackets;
-        uint64_t totalOutboundBytes = VoxelSendThread::_totalBytes;
-        uint64_t totalWastedBytes = VoxelSendThread::_totalWastedBytes;
-        uint64_t totalBytesOfOctalCodes = VoxelPacketData::getTotalBytesOfOctalCodes();
-        uint64_t totalBytesOfBitMasks = VoxelPacketData::getTotalBytesOfBitMasks();
-        uint64_t totalBytesOfColor = VoxelPacketData::getTotalBytesOfColor();
+        mg_printf(connection, "%s Outbound Packet Statistics...\r\n", theServer->getMyServerName());
+        uint64_t totalOutboundPackets = OctreeSendThread::_totalPackets;
+        uint64_t totalOutboundBytes = OctreeSendThread::_totalBytes;
+        uint64_t totalWastedBytes = OctreeSendThread::_totalWastedBytes;
+        uint64_t totalBytesOfOctalCodes = OctreePacketData::getTotalBytesOfOctalCodes();
+        uint64_t totalBytesOfBitMasks = OctreePacketData::getTotalBytesOfBitMasks();
+        uint64_t totalBytesOfColor = OctreePacketData::getTotalBytesOfColor();
 
         const int COLUMN_WIDTH = 10;
         mg_printf(connection, "           Total Outbound Packets: %s packets\r\n",
@@ -296,36 +280,37 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
         mg_printf(connection, "%s", "\r\n");
 
         // display inbound packet stats
-        mg_printf(connection, "%s", "Voxel Edit Statistics... [RESET]\r\n");
-        uint64_t averageTransitTimePerPacket = theServer->_voxelServerPacketProcessor->getAverageTransitTimePerPacket();
-        uint64_t averageProcessTimePerPacket = theServer->_voxelServerPacketProcessor->getAverageProcessTimePerPacket();
-        uint64_t averageLockWaitTimePerPacket = theServer->_voxelServerPacketProcessor->getAverageLockWaitTimePerPacket();
-        uint64_t averageProcessTimePerVoxel = theServer->_voxelServerPacketProcessor->getAverageProcessTimePerVoxel();
-        uint64_t averageLockWaitTimePerVoxel = theServer->_voxelServerPacketProcessor->getAverageLockWaitTimePerVoxel();
-        uint64_t totalVoxelsProcessed = theServer->_voxelServerPacketProcessor->getTotalVoxelsProcessed();
-        uint64_t totalPacketsProcessed = theServer->_voxelServerPacketProcessor->getTotalPacketsProcessed();
+        mg_printf(connection, "%s Edit Statistics... [RESET]\r\n", 
+                        theServer->getMyServerName());
+        uint64_t averageTransitTimePerPacket = theServer->_octreeInboundPacketProcessor->getAverageTransitTimePerPacket();
+        uint64_t averageProcessTimePerPacket = theServer->_octreeInboundPacketProcessor->getAverageProcessTimePerPacket();
+        uint64_t averageLockWaitTimePerPacket = theServer->_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket();
+        uint64_t averageProcessTimePerElement = theServer->_octreeInboundPacketProcessor->getAverageProcessTimePerElement();
+        uint64_t averageLockWaitTimePerElement = theServer->_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement();
+        uint64_t totalElementsProcessed = theServer->_octreeInboundPacketProcessor->getTotalElementsProcessed();
+        uint64_t totalPacketsProcessed = theServer->_octreeInboundPacketProcessor->getTotalPacketsProcessed();
 
-        float averageVoxelsPerPacket = totalPacketsProcessed == 0 ? 0 : totalVoxelsProcessed / totalPacketsProcessed;
+        float averageElementsPerPacket = totalPacketsProcessed == 0 ? 0 : totalElementsProcessed / totalPacketsProcessed;
 
         mg_printf(connection, "           Total Inbound Packets: %s packets\r\n",
             locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "            Total Inbound Voxels: %s voxels\r\n",
-            locale.toString((uint)totalVoxelsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "   Average Inbound Voxels/Packet: %f voxels/packet\r\n", averageVoxelsPerPacket);
+        mg_printf(connection, "          Total Inbound Elements: %s elements\r\n",
+            locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
+        mg_printf(connection, " Average Inbound Elements/Packet: %f elements/packet\r\n", averageElementsPerPacket);
         mg_printf(connection, "     Average Transit Time/Packet: %s usecs\r\n", 
             locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
         mg_printf(connection, "     Average Process Time/Packet: %s usecs\r\n",
             locale.toString((uint)averageProcessTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
         mg_printf(connection, "   Average Wait Lock Time/Packet: %s usecs\r\n", 
             locale.toString((uint)averageLockWaitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "      Average Process Time/Voxel: %s usecs\r\n",
-            locale.toString((uint)averageProcessTimePerVoxel).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "    Average Wait Lock Time/Voxel: %s usecs\r\n", 
-            locale.toString((uint)averageLockWaitTimePerVoxel).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
+        mg_printf(connection, "    Average Process Time/Element: %s usecs\r\n",
+            locale.toString((uint)averageProcessTimePerElement).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
+        mg_printf(connection, "  Average Wait Lock Time/Element: %s usecs\r\n", 
+            locale.toString((uint)averageLockWaitTimePerElement).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
 
 
         int senderNumber = 0;
-        NodeToSenderStatsMap& allSenderStats = theServer->_voxelServerPacketProcessor->getSingleSenderStats();
+        NodeToSenderStatsMap& allSenderStats = theServer->_octreeInboundPacketProcessor->getSingleSenderStats();
         for (NodeToSenderStatsMapIterator i = allSenderStats.begin(); i != allSenderStats.end(); i++) {
             senderNumber++;
             QUuid senderID = i->first;
@@ -337,28 +322,28 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
             averageTransitTimePerPacket = senderStats.getAverageTransitTimePerPacket();
             averageProcessTimePerPacket = senderStats.getAverageProcessTimePerPacket();
             averageLockWaitTimePerPacket = senderStats.getAverageLockWaitTimePerPacket();
-            averageProcessTimePerVoxel = senderStats.getAverageProcessTimePerVoxel();
-            averageLockWaitTimePerVoxel = senderStats.getAverageLockWaitTimePerVoxel();
-            totalVoxelsProcessed = senderStats.getTotalVoxelsProcessed();
+            averageProcessTimePerElement = senderStats.getAverageProcessTimePerElement();
+            averageLockWaitTimePerElement = senderStats.getAverageLockWaitTimePerElement();
+            totalElementsProcessed = senderStats.getTotalElementsProcessed();
             totalPacketsProcessed = senderStats.getTotalPacketsProcessed();
 
-            averageVoxelsPerPacket = totalPacketsProcessed == 0 ? 0 : totalVoxelsProcessed / totalPacketsProcessed;
+            averageElementsPerPacket = totalPacketsProcessed == 0 ? 0 : totalElementsProcessed / totalPacketsProcessed;
 
             mg_printf(connection, "               Total Inbound Packets: %s packets\r\n",
                 locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "                Total Inbound Voxels: %s voxels\r\n",
-                locale.toString((uint)totalVoxelsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "       Average Inbound Voxels/Packet: %f voxels/packet\r\n", averageVoxelsPerPacket);
+            mg_printf(connection, "              Total Inbound Elements: %s elements\r\n",
+                locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
+            mg_printf(connection, "     Average Inbound Elements/Packet: %f elements/packet\r\n", averageElementsPerPacket);
             mg_printf(connection, "         Average Transit Time/Packet: %s usecs\r\n", 
                 locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
             mg_printf(connection, "         Average Process Time/Packet: %s usecs\r\n",
                 locale.toString((uint)averageProcessTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
             mg_printf(connection, "       Average Wait Lock Time/Packet: %s usecs\r\n", 
                 locale.toString((uint)averageLockWaitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "          Average Process Time/Voxel: %s usecs\r\n",
-                locale.toString((uint)averageProcessTimePerVoxel).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "        Average Wait Lock Time/Voxel: %s usecs\r\n", 
-                locale.toString((uint)averageLockWaitTimePerVoxel).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
+            mg_printf(connection, "        Average Process Time/Element: %s usecs\r\n",
+                locale.toString((uint)averageProcessTimePerElement).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
+            mg_printf(connection, "      Average Wait Lock Time/Element: %s usecs\r\n", 
+                locale.toString((uint)averageLockWaitTimePerElement).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
 
         }
 
@@ -368,7 +353,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
 
         // display memory usage stats
         mg_printf(connection, "%s", "Current Memory Usage Statistics\r\n");
-        mg_printf(connection, "\r\nVoxelTreeElement size... %ld bytes\r\n", sizeof(VoxelTreeElement));
+        mg_printf(connection, "\r\nOctreeElement size... %ld bytes\r\n", sizeof(OctreeElement));
         mg_printf(connection, "%s", "\r\n");
 
         const char* memoryScaleLabel;
@@ -383,7 +368,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
             memoryScale = GIGABYTES;
         }
 
-        mg_printf(connection, "Voxel Node Memory Usage:         %8.2f %s\r\n", 
+        mg_printf(connection, "Element Node Memory Usage:       %8.2f %s\r\n", 
             OctreeElement::getVoxelMemoryUsage() / memoryScale, memoryScaleLabel);
         mg_printf(connection, "Octcode Memory Usage:            %8.2f %s\r\n", 
             OctreeElement::getOctcodeMemoryUsage() / memoryScale, memoryScaleLabel);
@@ -459,18 +444,18 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
 }
 
 
-void VoxelServer::setArguments(int argc, char** argv) {
+void OctreeServer::setArguments(int argc, char** argv) {
     _argc = argc;
     _argv = const_cast(argv);
 
-    qDebug("VoxelServer::setArguments()\n");
+    qDebug("OctreeServer::setArguments()\n");
     for (int i = 0; i < _argc; i++) {
         qDebug("_argv[%d]=%s\n", i, _argv[i]);
     }
 
 }
 
-void VoxelServer::parsePayload() {
+void OctreeServer::parsePayload() {
     
     if (getNumPayloadBytes() > 0) {
         QString config((const char*) _payload);
@@ -480,7 +465,7 @@ void VoxelServer::parsePayload() {
         
         int argCount = configList.size() + 1;
 
-        qDebug("VoxelServer::parsePayload()... argCount=%d\n",argCount);
+        qDebug("OctreeServer::parsePayload()... argCount=%d\n",argCount);
 
         _parsedArgV = new char*[argCount];
         const char* dummy = "config-from-payload";
@@ -491,17 +476,19 @@ void VoxelServer::parsePayload() {
             QString configItem = configList.at(i-1);
             _parsedArgV[i] = new char[configItem.length() + sizeof(char)];
             strcpy(_parsedArgV[i], configItem.toLocal8Bit().constData());
-            qDebug("VoxelServer::parsePayload()... _parsedArgV[%d]=%s\n", i, _parsedArgV[i]);
+            qDebug("OctreeServer::parsePayload()... _parsedArgV[%d]=%s\n", i, _parsedArgV[i]);
         }
 
         setArguments(argCount, _parsedArgV);
     }
 }
 
-void VoxelServer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
+void OctreeServer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
     NodeList* nodeList = NodeList::getInstance();
     
-    if (dataByteArray[0] == PACKET_TYPE_VOXEL_QUERY) {
+    PACKET_TYPE packetType = dataByteArray[0];
+    
+    if (packetType == getMyQueryMessageType()) {
         bool debug = false;
         if (debug) {
             qDebug("Got PACKET_TYPE_VOXEL_QUERY at %llu.\n", usecTimestampNow());
@@ -524,56 +511,38 @@ void VoxelServer::processDatagram(const QByteArray& dataByteArray, const HifiSoc
                 // this means they've heard from us and can reply, let's assume public is active
                 node->activatePublicSocket();
             }
-            VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData();
-            if (nodeData && !nodeData->isVoxelSendThreadInitalized()) {
-                nodeData->initializeVoxelSendThread(this);
+            OctreeQueryNode* nodeData = (OctreeQueryNode*) node->getLinkedData();
+            if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
+                nodeData->initializeOctreeSendThread(this);
             }
         }
-    } else if (dataByteArray[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) {
-        if (_jurisdictionSender) {
-            _jurisdictionSender->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(),
-                                                     dataByteArray.size());
-        }
-    } else if (_voxelServerPacketProcessor &&
-               (dataByteArray[0] == PACKET_TYPE_SET_VOXEL
-                || dataByteArray[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE
-                || dataByteArray[0] == PACKET_TYPE_ERASE_VOXEL)) {
-                   
-                   
-                   const char* messageName;
-                   switch (dataByteArray[0]) {
-                       case PACKET_TYPE_SET_VOXEL:
-                           messageName = "PACKET_TYPE_SET_VOXEL";
-                           break;
-                       case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE:
-                           messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE";
-                           break;
-                       case PACKET_TYPE_ERASE_VOXEL:
-                           messageName = "PACKET_TYPE_ERASE_VOXEL";
-                           break;
-                   }
-                   _voxelServerPacketProcessor->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(),
+    } else if (_jurisdictionSender && packetType == PACKET_TYPE_JURISDICTION_REQUEST) {
+        _jurisdictionSender->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(),
+                                                 dataByteArray.size());
+    } else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) {
+       _octreeInboundPacketProcessor->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(),
                                                                     dataByteArray.size());
-               } else {
-                   // let processNodeData handle it.
-                   NodeList::getInstance()->processNodeData(senderSockAddr, (unsigned char*) dataByteArray.data(),
-                                                            dataByteArray.size());
-               }
+   } else {
+       // let processNodeData handle it.
+       NodeList::getInstance()->processNodeData(senderSockAddr, (unsigned char*) dataByteArray.data(),
+                                                dataByteArray.size());
+    }
 }
 
-//int main(int argc, const char * argv[]) {
-void VoxelServer::run() {
-    
-    const char VOXEL_SERVER_LOGGING_TARGET_NAME[] = "voxel-server";
+void OctreeServer::run() {
+    // Before we do anything else, create our tree...
+    _tree = createTree();
     
     // change the logging target name while this is running
-    Logging::setTargetName(VOXEL_SERVER_LOGGING_TARGET_NAME);
+    Logging::setTargetName(getMyLoggingServerTargetName());
 
     // Now would be a good time to parse our arguments, if we got them as assignment
     if (getNumPayloadBytes() > 0) {
         parsePayload();
     }
 
+    beforeRun(); // after payload has been processed
+
     qInstallMessageHandler(Logging::verboseMessageHandler);
     
     const char* STATUS_PORT = "--statusPort";
@@ -610,27 +579,8 @@ void VoxelServer::run() {
         }
     }
 
-    // should we send environments? Default is yes, but this command line suppresses sending
-    const char* DUMP_VOXELS_ON_MOVE = "--dumpVoxelsOnMove";
-    _dumpVoxelsOnMove = cmdOptionExists(_argc, _argv, DUMP_VOXELS_ON_MOVE);
-    qDebug("dumpVoxelsOnMove=%s\n", debug::valueOf(_dumpVoxelsOnMove));
-    
-    // should we send environments? Default is yes, but this command line suppresses sending
-    const char* SEND_ENVIRONMENTS = "--sendEnvironments";
-    bool dontSendEnvironments =  !cmdOptionExists(_argc, _argv, SEND_ENVIRONMENTS);
-    if (dontSendEnvironments) {
-        qDebug("Sending environments suppressed...\n");
-        _sendEnvironments = false;
-    } else { 
-        // should we send environments? Default is yes, but this command line suppresses sending
-        const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment";
-        _sendMinimalEnvironment =  cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT);
-        qDebug("Using Minimal Environment=%s\n", debug::valueOf(_sendMinimalEnvironment));
-    }
-    qDebug("Sending environments=%s\n", debug::valueOf(_sendEnvironments));
-    
     NodeList* nodeList = NodeList::getInstance();
-    nodeList->setOwnerType(NODE_TYPE_VOXEL_SERVER);
+    nodeList->setOwnerType(getMyNodeType());
     
     // we need to ask the DS about agents so we can ping/reply with them
     const char nodeTypesOfInterest[] = { NODE_TYPE_AGENT, NODE_TYPE_ANIMATION_SERVER};
@@ -639,69 +589,52 @@ void VoxelServer::run() {
     setvbuf(stdout, NULL, _IOLBF, 0);
 
     // tell our NodeList about our desire to get notifications
-    nodeList->addHook(&_nodeWatcher);
-    nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode;
+    nodeList->addHook(this);
+    nodeList->linkedDataCreateCallback = &OctreeServer::attachQueryNodeToNode;
 
     nodeList->startSilentNodeRemovalThread();
     srand((unsigned)time(0));
     
-    const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats";
-    _displayVoxelStats =  cmdOptionExists(_argc, _argv, DISPLAY_VOXEL_STATS);
-    qDebug("displayVoxelStats=%s\n", debug::valueOf(_displayVoxelStats));
-
     const char* VERBOSE_DEBUG = "--verboseDebug";
     _verboseDebug =  cmdOptionExists(_argc, _argv, VERBOSE_DEBUG);
     qDebug("verboseDebug=%s\n", debug::valueOf(_verboseDebug));
 
-    const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
-    _debugVoxelSending =  cmdOptionExists(_argc, _argv, DEBUG_VOXEL_SENDING);
-    qDebug("debugVoxelSending=%s\n", debug::valueOf(_debugVoxelSending));
+    const char* DEBUG_SENDING = "--debugSending";
+    _debugSending =  cmdOptionExists(_argc, _argv, DEBUG_SENDING);
+    qDebug("debugSending=%s\n", debug::valueOf(_debugSending));
 
-    const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving";
-    _debugVoxelReceiving =  cmdOptionExists(_argc, _argv, DEBUG_VOXEL_RECEIVING);
-    qDebug("debugVoxelReceiving=%s\n", debug::valueOf(_debugVoxelReceiving));
+    const char* DEBUG_RECEIVING = "--debugReceiving";
+    _debugReceiving =  cmdOptionExists(_argc, _argv, DEBUG_RECEIVING);
+    qDebug("debugReceiving=%s\n", debug::valueOf(_debugReceiving));
 
-    const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug";
-    _shouldShowAnimationDebug =  cmdOptionExists(_argc, _argv, WANT_ANIMATION_DEBUG);
-    qDebug("shouldShowAnimationDebug=%s\n", debug::valueOf(_shouldShowAnimationDebug));
-
-    // By default we will voxel persist, if you want to disable this, then pass in this parameter
-    const char* NO_VOXEL_PERSIST = "--NoVoxelPersist";
-    if (cmdOptionExists(_argc, _argv, NO_VOXEL_PERSIST)) {
-        _wantVoxelPersist = false;
+    // By default we will persist, if you want to disable this, then pass in this parameter
+    const char* NO_PERSIST = "--NoPersist";
+    if (cmdOptionExists(_argc, _argv, NO_PERSIST)) {
+        _wantPersist = false;
     }
-    qDebug("wantVoxelPersist=%s\n", debug::valueOf(_wantVoxelPersist));
+    qDebug("wantPersist=%s\n", debug::valueOf(_wantPersist));
 
-    // if we want Voxel Persistence, set up the local file and persist thread
-    if (_wantVoxelPersist) {
+    // if we want Persistence, set up the local file and persist thread
+    if (_wantPersist) {
 
         // Check to see if the user passed in a command line option for setting packet send rate
-        const char* VOXELS_PERSIST_FILENAME = "--voxelsPersistFilename";
-        const char* voxelsPersistFilenameParameter = getCmdOption(_argc, _argv, VOXELS_PERSIST_FILENAME);
-        if (voxelsPersistFilenameParameter) {
-            strcpy(_voxelPersistFilename, voxelsPersistFilenameParameter);
+        const char* PERSIST_FILENAME = "--persistFilename";
+        const char* persistFilenameParameter = getCmdOption(_argc, _argv, PERSIST_FILENAME);
+        if (persistFilenameParameter) {
+            strcpy(_persistFilename, persistFilenameParameter);
         } else {
-            //strcpy(voxelPersistFilename, _wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
-            strcpy(_voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE);
+            strcpy(_persistFilename, getMyDefaultPersistFilename());
         }
 
-        qDebug("voxelPersistFilename=%s\n", _voxelPersistFilename);
+        qDebug("persistFilename=%s\n", _persistFilename);
 
-        // now set up VoxelPersistThread
-        _voxelPersistThread = new VoxelPersistThread(&_serverTree, _voxelPersistFilename);
-        if (_voxelPersistThread) {
-            _voxelPersistThread->initialize(true);
+        // now set up PersistThread
+        _persistThread = new OctreePersistThread(_tree, _persistFilename);
+        if (_persistThread) {
+            _persistThread->initialize(true);
         }
     }
 
-    // Check to see if the user passed in a command line option for loading an old style local
-    // Voxel File. If so, load it now. This is not the same as a voxel persist file
-    const char* INPUT_FILE = "-i";
-    const char* voxelsFilename = getCmdOption(_argc, _argv, INPUT_FILE);
-    if (voxelsFilename) {
-        _serverTree.readFromSVOFile(voxelsFilename);
-    }
-
     // Check to see if the user passed in a command line option for setting packet send rate
     const char* PACKETS_PER_SECOND = "--packetsPerSecond";
     const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND);
@@ -721,10 +654,10 @@ void VoxelServer::run() {
         _jurisdictionSender->initialize(true);
     }
     
-    // set up our VoxelServerPacketProcessor
-    _voxelServerPacketProcessor = new VoxelServerPacketProcessor(this);
-    if (_voxelServerPacketProcessor) {
-        _voxelServerPacketProcessor->initialize(true);
+    // set up our OctreeServerPacketProcessor
+    _octreeInboundPacketProcessor = new OctreeInboundPacketProcessor(this);
+    if (_octreeInboundPacketProcessor) {
+        _octreeInboundPacketProcessor->initialize(true);
     }
 
     // Convert now to tm struct for local timezone
@@ -766,23 +699,23 @@ void VoxelServer::run() {
         delete _jurisdictionSender;
     }
 
-    if (_voxelServerPacketProcessor) {
-        _voxelServerPacketProcessor->terminate();
-        delete _voxelServerPacketProcessor;
+    if (_octreeInboundPacketProcessor) {
+        _octreeInboundPacketProcessor->terminate();
+        delete _octreeInboundPacketProcessor;
     }
 
-    if (_voxelPersistThread) {
-        _voxelPersistThread->terminate();
-        delete _voxelPersistThread;
+    if (_persistThread) {
+        _persistThread->terminate();
+        delete _persistThread;
     }
     
     // tell our NodeList we're done with notifications
-    nodeList->removeHook(&_nodeWatcher);
+    nodeList->removeHook(this);
 
     delete _jurisdiction;
     _jurisdiction = NULL;
 
-    qDebug() << "VoxelServer::run()... DONE\n";
+    qDebug() << "OctreeServer::run()... DONE\n";
 }
 
 
diff --git a/libraries/octree-server/src/OctreeServer.h b/libraries/octree-server/src/OctreeServer.h
new file mode 100644
index 0000000000..39fb9ee990
--- /dev/null
+++ b/libraries/octree-server/src/OctreeServer.h
@@ -0,0 +1,98 @@
+//
+//  OctreeServer.h
+//  voxel-server
+//
+//  Created by Brad Hefta-Gaub on 8/21/13
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+//
+
+#ifndef __octree_server__OctreeServer__
+#define __octree_server__OctreeServer__
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "OctreePersistThread.h"
+#include "OctreeSendThread.h"
+#include "OctreeServerConsts.h"
+#include "OctreeInboundPacketProcessor.h"
+
+/// Handles assignments of type OctreeServer - sending octrees to various clients.
+class OctreeServer : public ThreadedAssignment, public NodeListHook {
+public:                
+    OctreeServer(const unsigned char* dataBuffer, int numBytes);
+    ~OctreeServer();
+    
+    /// allows setting of run arguments
+    void setArguments(int argc, char** argv);
+
+    bool wantsDebugSending() const { return _debugSending; }
+    bool wantsDebugReceiving() const { return _debugReceiving; }
+    bool wantsVerboseDebug() const { return _verboseDebug; }
+
+    Octree* getOctree() { return _tree; }
+    JurisdictionMap* getJurisdiction() { return _jurisdiction; }
+    
+    int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; }
+    static OctreeServer* GetInstance() { return _theInstance; }
+    
+    bool isInitialLoadComplete() const { return (_persistThread) ? _persistThread->isInitialLoadComplete() : true; }
+    time_t* getLoadCompleted() { return (_persistThread) ? _persistThread->getLoadCompleted() : NULL; }
+    uint64_t getLoadElapsedTime() const { return (_persistThread) ? _persistThread->getLoadElapsedTime() : 0; }
+
+    // Subclasses must implement these methods    
+    virtual OctreeQueryNode* createOctreeQueryNode(Node* newNode) = 0;
+    virtual Octree* createTree() = 0;
+    virtual unsigned char getMyNodeType() const = 0;
+    virtual PACKET_TYPE getMyQueryMessageType() const = 0;
+    virtual const char* getMyServerName() const = 0;
+    virtual const char* getMyLoggingServerTargetName() const = 0;
+    virtual const char* getMyDefaultPersistFilename() const = 0;
+    
+    // subclass may implement these method
+    virtual void beforeRun() { };
+    virtual bool hasSpecialPacketToSend() { return false; }
+    virtual int sendSpecialPacket(Node* node) { return 0; }
+
+    static void attachQueryNodeToNode(Node* newNode);
+
+    // NodeListHook 
+    virtual void nodeAdded(Node* node);
+    virtual void nodeKilled(Node* node);
+
+public slots:
+    /// runs the voxel server assignment
+    void run();
+    void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);
+
+protected:
+    int _argc;
+    const char** _argv;
+    char** _parsedArgV;
+
+    char _persistFilename[MAX_FILENAME_LENGTH];
+    int _packetsPerClientPerInterval;
+    Octree* _tree; // this IS a reaveraging tree 
+    bool _wantPersist;
+    bool _debugSending;
+    bool _debugReceiving;
+    bool _verboseDebug;
+    JurisdictionMap* _jurisdiction;
+    JurisdictionSender* _jurisdictionSender;
+    OctreeInboundPacketProcessor* _octreeInboundPacketProcessor;
+    OctreePersistThread* _persistThread;
+
+    void parsePayload();
+    void initMongoose(int port);
+    static int civetwebRequestHandler(struct mg_connection *connection);
+    static OctreeServer* _theInstance;
+    time_t _started;
+    uint64_t _startedUSecs;
+};
+
+#endif // __octree_server__OctreeServer__
diff --git a/libraries/octree-server/src/OctreeServerConsts.h b/libraries/octree-server/src/OctreeServerConsts.h
new file mode 100644
index 0000000000..fae03a73ca
--- /dev/null
+++ b/libraries/octree-server/src/OctreeServerConsts.h
@@ -0,0 +1,21 @@
+//  OctreeServerConsts.h
+//  octree-server
+//
+//  Created by Brad Hefta-Gaub on 12/4/13
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+//
+
+#ifndef __octree_server__OctreeServerConsts__
+#define __octree_server__OctreeServerConsts__
+
+#include 
+#include  // for MAX_PACKET_SIZE
+#include 
+
+const int MAX_FILENAME_LENGTH = 1024;
+const int INTERVALS_PER_SECOND = 60;
+const int OCTREE_SEND_INTERVAL_USECS = (1000 * 1000)/INTERVALS_PER_SECOND;
+const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
+
+#endif // __octree_server__OctreeServerConsts__
diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp
index 3213e11940..5a356c0b7c 100644
--- a/libraries/octree/src/JurisdictionListener.cpp
+++ b/libraries/octree/src/JurisdictionListener.cpp
@@ -42,7 +42,7 @@ void JurisdictionListener::nodeKilled(Node* node) {
 bool JurisdictionListener::queueJurisdictionRequest() {
     static unsigned char buffer[MAX_PACKET_SIZE];
     unsigned char* bufferOut = &buffer[0];
-    ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_VOXEL_JURISDICTION_REQUEST);
+    ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_JURISDICTION_REQUEST);
     int nodeCount = 0;
 
     NodeList* nodeList = NodeList::getInstance();
@@ -65,7 +65,7 @@ bool JurisdictionListener::queueJurisdictionRequest() {
 }
 
 void JurisdictionListener::processPacket(const HifiSockAddr& senderAddress, unsigned char*  packetData, ssize_t packetLength) {
-    if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION) {
+    if (packetData[0] == PACKET_TYPE_JURISDICTION) {
         Node* node = NodeList::getInstance()->nodeWithAddress(senderAddress);
         if (node) {
             QUuid nodeUUID = node->getUUID();
diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h
index a05601169b..e8d3ec32a9 100644
--- a/libraries/octree/src/JurisdictionListener.h
+++ b/libraries/octree/src/JurisdictionListener.h
@@ -17,8 +17,8 @@
 
 #include "JurisdictionMap.h"
 
-/// Sends out PACKET_TYPE_VOXEL_JURISDICTION_REQUEST packets to all voxel servers and then listens for and processes
-/// the PACKET_TYPE_VOXEL_JURISDICTION packets it receives in order to maintain an accurate state of all jurisidictions
+/// Sends out PACKET_TYPE_JURISDICTION_REQUEST packets to all voxel servers and then listens for and processes
+/// the PACKET_TYPE_JURISDICTION packets it receives in order to maintain an accurate state of all jurisidictions
 /// within the domain. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets
 /// and adding them to the processing queue by calling queueReceivedPacket()
 class JurisdictionListener : public NodeListHook, public PacketSender, public ReceivedPacketProcessor {
@@ -39,7 +39,7 @@ public:
     void nodeKilled(Node* node);
 
 protected:
-    /// Callback for processing of received packets. Will process any queued PACKET_TYPE_VOXEL_JURISDICTION and update the
+    /// Callback for processing of received packets. Will process any queued PACKET_TYPE_JURISDICTION and update the
     /// jurisdiction map member variable
     /// \param sockaddr& senderAddress the address of the sender
     /// \param packetData pointer to received data
diff --git a/libraries/octree/src/JurisdictionMap.cpp b/libraries/octree/src/JurisdictionMap.cpp
index bd2f703cdb..b104aee14d 100644
--- a/libraries/octree/src/JurisdictionMap.cpp
+++ b/libraries/octree/src/JurisdictionMap.cpp
@@ -263,7 +263,7 @@ bool JurisdictionMap::writeToFile(const char* filename) {
 int JurisdictionMap::packEmptyJurisdictionIntoMessage(unsigned char* destinationBuffer, int availableBytes) {
     unsigned char* bufferStart = destinationBuffer;
     
-    int headerLength = populateTypeAndVersion(destinationBuffer, PACKET_TYPE_VOXEL_JURISDICTION);
+    int headerLength = populateTypeAndVersion(destinationBuffer, PACKET_TYPE_JURISDICTION);
     destinationBuffer += headerLength;
 
     // No root or end node details to pack!
@@ -277,7 +277,7 @@ int JurisdictionMap::packEmptyJurisdictionIntoMessage(unsigned char* destination
 int JurisdictionMap::packIntoMessage(unsigned char* destinationBuffer, int availableBytes) {
     unsigned char* bufferStart = destinationBuffer;
     
-    int headerLength = populateTypeAndVersion(destinationBuffer, PACKET_TYPE_VOXEL_JURISDICTION);
+    int headerLength = populateTypeAndVersion(destinationBuffer, PACKET_TYPE_JURISDICTION);
     destinationBuffer += headerLength;
 
     // add the root jurisdiction
diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp
index 9bb729f66a..0428128e21 100644
--- a/libraries/octree/src/JurisdictionSender.cpp
+++ b/libraries/octree/src/JurisdictionSender.cpp
@@ -30,7 +30,7 @@ JurisdictionSender::~JurisdictionSender() {
 
 
 void JurisdictionSender::processPacket(const HifiSockAddr& senderAddress, unsigned char*  packetData, ssize_t packetLength) {
-    if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) {
+    if (packetData[0] == PACKET_TYPE_JURISDICTION_REQUEST) {
         Node* node = NodeList::getInstance()->nodeWithAddress(senderAddress);
         if (node) {
             QUuid nodeUUID = node->getUUID();
diff --git a/libraries/octree/src/JurisdictionSender.h b/libraries/octree/src/JurisdictionSender.h
index 5f61d41dea..3f5a3855d5 100644
--- a/libraries/octree/src/JurisdictionSender.h
+++ b/libraries/octree/src/JurisdictionSender.h
@@ -17,7 +17,7 @@
 #include 
 #include "JurisdictionMap.h"
 
-/// Will process PACKET_TYPE_VOXEL_JURISDICTION_REQUEST packets and send out PACKET_TYPE_VOXEL_JURISDICTION packets
+/// Will process PACKET_TYPE_JURISDICTION_REQUEST packets and send out PACKET_TYPE_JURISDICTION packets
 /// to requesting parties. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets
 /// and adding them to the processing queue by calling queueReceivedPacket()
 class JurisdictionSender : public PacketSender, public ReceivedPacketProcessor {
diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h
index 1cdd789a3c..564184caf5 100644
--- a/libraries/octree/src/Octree.h
+++ b/libraries/octree/src/Octree.h
@@ -180,6 +180,10 @@ public:
     
     virtual OctreeElement* createNewElement(unsigned char * octalCode = NULL) const = 0;
 
+    virtual bool handlesEditPacketType(PACKET_TYPE packetType) const { return false; }
+    virtual int processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength,
+                    unsigned char* editData, int maxLength) { return 0; }
+
     OctreeElement* getRoot() { return _rootNode; }
 
     void eraseAllOctreeElements();
@@ -250,7 +254,6 @@ public slots:
 
 protected:
     void deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraData);
-    void readCodeColorBufferToTreeRecursion(OctreeElement* node, void* extraData);
 
     int encodeTreeBitstreamRecursion(OctreeElement* node, 
                                      OctreePacketData* packetData, OctreeElementBag& bag,
diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp
index 646cc3a05c..076e2cc118 100644
--- a/libraries/octree/src/OctreeSceneStats.cpp
+++ b/libraries/octree/src/OctreeSceneStats.cpp
@@ -379,7 +379,7 @@ void OctreeSceneStats::childBitsRemoved(bool includesExistsBits, bool includesCo
 int OctreeSceneStats::packIntoMessage(unsigned char* destinationBuffer, int availableBytes) {
     unsigned char* bufferStart = destinationBuffer;
     
-    int headerLength = populateTypeAndVersion(destinationBuffer, PACKET_TYPE_VOXEL_STATS);
+    int headerLength = populateTypeAndVersion(destinationBuffer, PACKET_TYPE_OCTREE_STATS);
     destinationBuffer += headerLength;
     
     memcpy(destinationBuffer, &_start, sizeof(_start));
diff --git a/libraries/particle-server/CMakeLists.txt b/libraries/particle-server/CMakeLists.txt
new file mode 100644
index 0000000000..5e14902f45
--- /dev/null
+++ b/libraries/particle-server/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(ROOT_DIR ../..)
+set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
+
+# setup for find modules
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
+
+set(TARGET_NAME particle-server)
+
+find_package(Qt5Widgets REQUIRED)
+
+include(${MACRO_DIR}/SetupHifiLibrary.cmake)
+
+setup_hifi_library(${TARGET_NAME} ${OPTIONAL_SRCS})
+
+qt5_use_modules(${TARGET_NAME} Widgets)
+
+# inluce GLM
+include(${MACRO_DIR}/IncludeGLM.cmake)
+include_glm(${TARGET_NAME} ${ROOT_DIR})
+
+# link in the shared library
+include(${MACRO_DIR}/LinkHifiLibrary.cmake)
+link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
+
+# link ZLIB
+find_package(ZLIB)
+include_directories(${ZLIB_INCLUDE_DIRS})
+target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
+
+link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
+link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR})
+link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
+
diff --git a/libraries/particle-server/src/ParticleNodeData.h b/libraries/particle-server/src/ParticleNodeData.h
new file mode 100644
index 0000000000..991c4c063c
--- /dev/null
+++ b/libraries/particle-server/src/ParticleNodeData.h
@@ -0,0 +1,22 @@
+//
+//  ParticleNodeData.h
+//  hifi
+//
+//  Created by Brad Hefta-Gaub on 12/4/13
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+//
+
+#ifndef __hifi__ParticleNodeData__
+#define __hifi__ParticleNodeData__
+
+#include 
+#include 
+
+class ParticleNodeData : public OctreeQueryNode {
+public:
+    ParticleNodeData(Node* owningNode) : OctreeQueryNode(owningNode) {  };
+    virtual PACKET_TYPE getMyPacketType() const { return PACKET_TYPE_PARTICLE_DATA; }
+};
+
+#endif /* defined(__hifi__ParticleNodeData__) */
diff --git a/libraries/particle-server/src/ParticleServer.cpp b/libraries/particle-server/src/ParticleServer.cpp
new file mode 100644
index 0000000000..bc6c60f712
--- /dev/null
+++ b/libraries/particle-server/src/ParticleServer.cpp
@@ -0,0 +1,37 @@
+//
+//  ParticleServer.cpp
+//  hifi
+//
+//  Created by Brad Hefta-Gaub on 12/4/13
+//  Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
+//
+
+#include 
+
+#include "ParticleServer.h"
+#include "ParticleServerConsts.h"
+#include "ParticleNodeData.h"
+
+const char* PARTICLE_SERVER_NAME = "Particle";
+const char* PARTICLE_SERVER_LOGGING_TARGET_NAME = "particle-server";
+const char* LOCAL_PARTICLES_PERSIST_FILE = "resources/particles.svo";
+
+ParticleServer::ParticleServer(const unsigned char* dataBuffer, int numBytes) : OctreeServer(dataBuffer, numBytes) {
+    // nothing special to do here...
+}
+
+ParticleServer::~ParticleServer() {
+    // nothing special to do here...
+}
+
+OctreeQueryNode* ParticleServer::createOctreeQueryNode(Node* newNode) {
+    return new ParticleNodeData(newNode);
+}
+
+Octree* ParticleServer::createTree() {
+    return new ParticleTree(true);
+}
+
+void ParticleServer::beforeRun() {
+    // nothing special to do...
+}
diff --git a/libraries/particle-server/src/ParticleServer.h b/libraries/particle-server/src/ParticleServer.h
new file mode 100644
index 0000000000..4655f697bb
--- /dev/null
+++ b/libraries/particle-server/src/ParticleServer.h
@@ -0,0 +1,38 @@
+//
+//  ParticleServer.h
+//  particle-server
+//
+//  Created by Brad Hefta-Gaub on 12/2/13
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+//
+
+#ifndef __particle_server__ParticleServer__
+#define __particle_server__ParticleServer__
+
+#include 
+
+#include "ParticleServerConsts.h"
+
+/// Handles assignments of type ParticleServer - sending particles to various clients.
+class ParticleServer : public OctreeServer {
+public:                
+    ParticleServer(const unsigned char* dataBuffer, int numBytes);
+    ~ParticleServer();
+
+    // Subclasses must implement these methods    
+    virtual OctreeQueryNode* createOctreeQueryNode(Node* newNode);
+    virtual Octree* createTree();
+    virtual unsigned char getMyNodeType() const { return NODE_TYPE_PARTICLE_SERVER; }
+    virtual PACKET_TYPE getMyQueryMessageType() const { return PACKET_TYPE_PARTICLE_QUERY; }
+    virtual const char* getMyServerName() const { return PARTICLE_SERVER_NAME; }
+    virtual const char* getMyLoggingServerTargetName() const { return PARTICLE_SERVER_LOGGING_TARGET_NAME; }
+    virtual const char* getMyDefaultPersistFilename() const { return LOCAL_PARTICLES_PERSIST_FILE; }
+    
+    // subclass may implement these method
+    virtual void beforeRun();
+
+private:
+};
+
+#endif // __particle_server__ParticleServer__
diff --git a/libraries/particle-server/src/ParticleServerConsts.h b/libraries/particle-server/src/ParticleServerConsts.h
new file mode 100644
index 0000000000..5ac2a1534b
--- /dev/null
+++ b/libraries/particle-server/src/ParticleServerConsts.h
@@ -0,0 +1,16 @@
+//  ParticleServerConsts.h
+//  particle-server
+//
+//  Created by Brad Hefta-Gaub on 8/21/13
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+//
+
+#ifndef __particle_server__ParticleServerConsts__
+#define __particle_server__ParticleServerConsts__
+
+extern const char* PARTICLE_SERVER_NAME;
+extern const char* PARTICLE_SERVER_LOGGING_TARGET_NAME;
+extern const char* LOCAL_PARTICLES_PERSIST_FILE;
+
+#endif // __particle_server__ParticleServerConsts__
diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt
new file mode 100644
index 0000000000..3bbff3b433
--- /dev/null
+++ b/libraries/particles/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(ROOT_DIR ../..)
+set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
+
+# setup for find modules
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
+
+set(TARGET_NAME particles)
+
+find_package(Qt5Widgets REQUIRED)
+
+include(${MACRO_DIR}/SetupHifiLibrary.cmake)
+setup_hifi_library(${TARGET_NAME})
+
+qt5_use_modules(${TARGET_NAME} Widgets)
+
+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_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
+
+# link ZLIB
+find_package(ZLIB)
+include_directories(${ZLIB_INCLUDE_DIRS})
+target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp
new file mode 100644
index 0000000000..99580e974b
--- /dev/null
+++ b/libraries/particles/src/ParticleTree.cpp
@@ -0,0 +1,19 @@
+//
+//  ParticleTree.cpp
+//  hifi
+//
+//  Created by Brad Hefta-Gaub on 12/4/13.
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+
+#include "ParticleTree.h"
+
+ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) {
+    _rootNode = createNewElement();
+}
+
+ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) const {
+    ParticleTreeElement* newElement = new ParticleTreeElement(octalCode); 
+    return newElement;
+}
+
diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h
new file mode 100644
index 0000000000..e53c314ed9
--- /dev/null
+++ b/libraries/particles/src/ParticleTree.h
@@ -0,0 +1,24 @@
+//
+//  ParticleTree.h
+//  hifi
+//
+//  Created by Brad Hefta-Gaub on 12/4/13.
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+
+#ifndef __hifi__ParticleTree__
+#define __hifi__ParticleTree__
+
+#include 
+#include "ParticleTreeElement.h"
+
+class ParticleTree : public Octree {
+    Q_OBJECT
+public:
+    ParticleTree(bool shouldReaverage = false);
+    virtual ParticleTreeElement* createNewElement(unsigned char * octalCode = NULL) const;
+    ParticleTreeElement* getRoot() { return (ParticleTreeElement*)_rootNode; }
+private:
+};
+
+#endif /* defined(__hifi__ParticleTree__) */
diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp
new file mode 100644
index 0000000000..e3a02b3275
--- /dev/null
+++ b/libraries/particles/src/ParticleTreeElement.cpp
@@ -0,0 +1,62 @@
+//
+//  ParticleTreeElement.cpp
+//  hifi
+//
+//  Created by Brad Hefta-Gaub on 12/4/13.
+//  Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
+//
+
+#include 
+
+#include "ParticleTree.h"
+#include "ParticleTreeElement.h"
+
+ParticleTreeElement::ParticleTreeElement(unsigned char* octalCode) : OctreeElement() { 
+    init(octalCode);
+};
+
+ParticleTreeElement::~ParticleTreeElement() {
+    _voxelMemoryUsage -= sizeof(ParticleTreeElement);
+}
+
+// This will be called primarily on addChildAt(), which means we're adding a child of our
+// own type to our own tree. This means we should initialize that child with any tree and type 
+// specific settings that our children must have. One example is out VoxelSystem, which
+// we know must match ours.
+OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) const {
+    ParticleTreeElement* newChild = new ParticleTreeElement(octalCode);
+    return newChild;
+}
+
+void ParticleTreeElement::init(unsigned char* octalCode) {
+    OctreeElement::init(octalCode);
+    _voxelMemoryUsage += sizeof(ParticleTreeElement);
+}
+
+bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const {
+    // will write to the encoded stream all of the contents of this element
+    return true;
+}
+
+
+int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, 
+            ReadBitstreamToTreeParams& args) { 
+            
+    // will read from the encoded stream all of the contents of this element
+    return 0;
+}
+
+// will average a "common reduced LOD view" from the the child elements...
+void ParticleTreeElement::calculateAverageFromChildren() {
+    // nothing to do here yet...
+}
+
+// will detect if children are leaves AND collapsable into the parent node
+// and in that case will collapse children and make this node
+// a leaf, returns TRUE if all the leaves are collapsed into a 
+// single node
+bool ParticleTreeElement::collapseChildren() {
+    // nothing to do here yet...
+    return false;
+}
+
diff --git a/libraries/particles/src/ParticleTreeElement.h b/libraries/particles/src/ParticleTreeElement.h
new file mode 100644
index 0000000000..e169db14b0
--- /dev/null
+++ b/libraries/particles/src/ParticleTreeElement.h
@@ -0,0 +1,45 @@
+//
+//  ParticleTreeElement.h
+//  hifi
+//
+//  Created by Brad Hefta-Gaub on 12/4/13.
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+//
+
+#ifndef __hifi__ParticleTreeElement__
+#define __hifi__ParticleTreeElement__
+
+#include 
+
+class ParticleTree;
+class ParticleTreeElement;
+
+class ParticleTreeElement : public OctreeElement {
+    friend class ParticleTree; // to allow createElement to new us...
+    
+    ParticleTreeElement(unsigned char* octalCode = NULL);
+
+    virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL) const;
+    
+public:
+    virtual ~ParticleTreeElement();
+    virtual void init(unsigned char * octalCode);
+
+    virtual bool hasContent() const { return isLeaf(); }
+    virtual void splitChildren() {}
+    virtual bool requiresSplit() const { return false; }
+    virtual bool appendElementData(OctreePacketData* packetData) const;
+    virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
+    virtual void calculateAverageFromChildren();
+    virtual bool collapseChildren();
+    virtual bool isRendered() const { return getShouldRender(); }
+
+    // type safe versions of OctreeElement methods
+    ParticleTreeElement* getChildAtIndex(int index) { return (ParticleTreeElement*)OctreeElement::getChildAtIndex(index); }
+    ParticleTreeElement* addChildAtIndex(int index) { return (ParticleTreeElement*)OctreeElement::addChildAtIndex(index); }
+    
+protected:
+};
+
+#endif /* defined(__hifi__ParticleTreeElement__) */
\ No newline at end of file
diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp
index 59b0bb60d1..4943098812 100644
--- a/libraries/shared/src/Assignment.cpp
+++ b/libraries/shared/src/Assignment.cpp
@@ -27,6 +27,8 @@ Assignment::Type Assignment::typeForNodeType(NODE_TYPE nodeType) {
             return Assignment::AgentType;
         case NODE_TYPE_VOXEL_SERVER:
             return Assignment::VoxelServerType;
+        case NODE_TYPE_PARTICLE_SERVER:
+            return Assignment::ParticleServerType;
         default:
             return Assignment::AllTypes;
     }
@@ -176,6 +178,8 @@ const char* Assignment::getTypeName() const {
             return "agent";
         case Assignment::VoxelServerType:
             return "voxel-server";
+        case Assignment::ParticleServerType:
+            return "particle-server";
         default:
             return "unknown";
     }
diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h
index ec7ae7f74f..1aac273e36 100644
--- a/libraries/shared/src/Assignment.h
+++ b/libraries/shared/src/Assignment.h
@@ -28,6 +28,7 @@ public:
         AvatarMixerType,
         AgentType,
         VoxelServerType,
+        ParticleServerType,
         AllTypes
     };
     
diff --git a/libraries/shared/src/NodeTypes.h b/libraries/shared/src/NodeTypes.h
index a9deebf333..c9723f4477 100644
--- a/libraries/shared/src/NodeTypes.h
+++ b/libraries/shared/src/NodeTypes.h
@@ -19,6 +19,8 @@
 typedef char NODE_TYPE;
 const NODE_TYPE NODE_TYPE_DOMAIN = 'D';
 const NODE_TYPE NODE_TYPE_VOXEL_SERVER = 'V';
+const NODE_TYPE NODE_TYPE_PARTICLE_SERVER = 'P';
+const NODE_TYPE NODE_TYPE_ENVIRONMENT_SERVER = 'E';
 const NODE_TYPE NODE_TYPE_AGENT = 'I';
 const NODE_TYPE NODE_TYPE_AUDIO_MIXER = 'M';
 const NODE_TYPE NODE_TYPE_AVATAR_MIXER = 'W';
diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp
index 6ca20141d4..d48ffdbaf1 100644
--- a/libraries/shared/src/PacketHeaders.cpp
+++ b/libraries/shared/src/PacketHeaders.cpp
@@ -28,7 +28,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
         case PACKET_TYPE_AVATAR_FACE_VIDEO:
             return 2;
 
-        case PACKET_TYPE_VOXEL_STATS:
+        case PACKET_TYPE_OCTREE_STATS:
             return 2;
        
         case PACKET_TYPE_DOMAIN:
@@ -39,9 +39,9 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
         case PACKET_TYPE_VOXEL_QUERY:
             return 2;
 
-        case PACKET_TYPE_SET_VOXEL:
-        case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE:
-        case PACKET_TYPE_ERASE_VOXEL:
+        case PACKET_TYPE_VOXEL_SET:
+        case PACKET_TYPE_VOXEL_SET_DESTRUCTIVE:
+        case PACKET_TYPE_VOXEL_ERASE:
             return 1;
 
         case PACKET_TYPE_VOXEL_DATA:
diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h
index 9f19291eff..ade4292918 100644
--- a/libraries/shared/src/PacketHeaders.h
+++ b/libraries/shared/src/PacketHeaders.h
@@ -40,12 +40,16 @@ const PACKET_TYPE PACKET_TYPE_DATA_SERVER_SEND = 'u';
 const PACKET_TYPE PACKET_TYPE_DATA_SERVER_CONFIRM = 'c';
 const PACKET_TYPE PACKET_TYPE_VOXEL_QUERY = 'q';
 const PACKET_TYPE PACKET_TYPE_VOXEL_DATA = 'V';
-const PACKET_TYPE PACKET_TYPE_VOXEL_STATS = '#';
-const PACKET_TYPE PACKET_TYPE_VOXEL_JURISDICTION = 'J';
-const PACKET_TYPE PACKET_TYPE_VOXEL_JURISDICTION_REQUEST = 'j';
-const PACKET_TYPE PACKET_TYPE_SET_VOXEL = 'S';
-const PACKET_TYPE PACKET_TYPE_SET_VOXEL_DESTRUCTIVE = 'O';
-const PACKET_TYPE PACKET_TYPE_ERASE_VOXEL = 'E';
+const PACKET_TYPE PACKET_TYPE_VOXEL_SET = 'S';
+const PACKET_TYPE PACKET_TYPE_VOXEL_SET_DESTRUCTIVE = 'O';
+const PACKET_TYPE PACKET_TYPE_VOXEL_ERASE = 'E';
+const PACKET_TYPE PACKET_TYPE_OCTREE_STATS = '#';
+const PACKET_TYPE PACKET_TYPE_JURISDICTION = 'J';
+const PACKET_TYPE PACKET_TYPE_JURISDICTION_REQUEST = 'j';
+const PACKET_TYPE PACKET_TYPE_PARTICLE_QUERY = 'Q';
+const PACKET_TYPE PACKET_TYPE_PARTICLE_DATA = 'v';
+const PACKET_TYPE PACKET_TYPE_PARTICLE_ADD = 'a';
+const PACKET_TYPE PACKET_TYPE_PARTICLE_ERASE = 'x';
 
 typedef char PACKET_VERSION;
 
diff --git a/libraries/voxel-server-library/src/NodeWatcher.cpp b/libraries/voxel-server-library/src/NodeWatcher.cpp
deleted file mode 100644
index 03384569b8..0000000000
--- a/libraries/voxel-server-library/src/NodeWatcher.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-//  NodeWatcher.h
-//  voxel-server
-//
-//  Created by Brad Hefta-Gaub on 8/21/13
-//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
-//
-//  Node List Hook that watches for Node's being killed in order to clean up node specific memory and threads
-//
-
-#include 
-#include "NodeWatcher.h"
-#include "VoxelNodeData.h"
-
-void NodeWatcher::nodeAdded(Node* node) {
-    // do nothing
-}
-
-void NodeWatcher::nodeKilled(Node* node) {
-    // Use this to cleanup our node
-    if (node->getType() == NODE_TYPE_AGENT) {
-        VoxelNodeData* nodeData = (VoxelNodeData*)node->getLinkedData();
-        if (nodeData) {
-            node->setLinkedData(NULL);
-            delete nodeData;
-        }
-    }
-};
diff --git a/libraries/voxel-server-library/src/NodeWatcher.h b/libraries/voxel-server-library/src/NodeWatcher.h
deleted file mode 100644
index a730f7d575..0000000000
--- a/libraries/voxel-server-library/src/NodeWatcher.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-//  NodeWatcher.h
-//  voxel-server
-//
-//  Created by Brad Hefta-Gaub on 8/21/13
-//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
-//
-//  Node List Hook that watches for Node's being killed in order to clean up node specific memory and threads
-//
-
-#ifndef __voxel_server__NodeWatcher__
-#define __voxel_server__NodeWatcher__
-
-#include 
-
-/// Voxel server's node watcher, which watches for nodes being killed and cleans up their data and threads
-class NodeWatcher : public virtual NodeListHook {
-public:
-    virtual void nodeAdded(Node* node);
-    virtual void nodeKilled(Node* node);
-};
-
-#endif // __voxel_server__NodeWatcher__
diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h
deleted file mode 100644
index 5fc41fbc72..0000000000
--- a/libraries/voxel-server-library/src/VoxelSendThread.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-//  VoxelSendThread.h
-//  voxel-server
-//
-//  Created by Brad Hefta-Gaub on 8/21/13
-//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
-//
-//  Threaded or non-threaded object for sending voxels to a client
-//
-
-#ifndef __voxel_server__VoxelSendThread__
-#define __voxel_server__VoxelSendThread__
-
-#include 
-#include 
-#include 
-#include 
-#include "VoxelNodeData.h"
-#include "VoxelServer.h"
-
-/// Threaded processor for sending voxel packets to a single client
-class VoxelSendThread : public virtual GenericThread {
-public:
-    VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer);
-
-    static uint64_t _totalBytes;
-    static uint64_t _totalWastedBytes;
-    static uint64_t _totalPackets;
-
-    static uint64_t _usleepTime;
-    static uint64_t _usleepCalls;
-
-protected:
-    /// Implements generic processing behavior for this thread.
-    virtual bool process();
-
-private:
-    QUuid _nodeUUID;
-    VoxelServer* _myServer;
-
-    int handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent);
-    int deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged);
-    
-    unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; // used by environment sending code
-    VoxelPacketData _packetData;
-};
-
-#endif // __voxel_server__VoxelSendThread__
diff --git a/libraries/voxel-server-library/src/VoxelServer.h b/libraries/voxel-server-library/src/VoxelServer.h
deleted file mode 100644
index f4923778c1..0000000000
--- a/libraries/voxel-server-library/src/VoxelServer.h
+++ /dev/null
@@ -1,103 +0,0 @@
-//
-//  VoxelServer.h
-//  voxel-server
-//
-//  Created by Brad Hefta-Gaub on 8/21/13
-//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
-//
-//
-
-#ifndef __voxel_server__VoxelServer__
-#define __voxel_server__VoxelServer__
-
-#include 
-#include 
-#include 
-
-#include 
-#include 
-
-#include "civetweb.h"
-
-#include "NodeWatcher.h"
-#include "VoxelPersistThread.h"
-#include "VoxelSendThread.h"
-#include "VoxelServerConsts.h"
-#include "VoxelServerPacketProcessor.h"
-
-/// Handles assignments of type VoxelServer - sending voxels to various clients.
-class VoxelServer : public ThreadedAssignment {
-public:                
-    VoxelServer(const unsigned char* dataBuffer, int numBytes);
-    
-    ~VoxelServer();
-    
-   
-    
-    /// allows setting of run arguments
-    void setArguments(int argc, char** argv);
-
-    bool wantsDebugVoxelSending() const { return _debugVoxelSending; }
-    bool wantsDebugVoxelReceiving() const { return _debugVoxelReceiving; }
-    bool wantsVerboseDebug() const { return _verboseDebug; }
-    bool wantShowAnimationDebug() const { return _shouldShowAnimationDebug; }
-    bool wantSendEnvironments() const { return _sendEnvironments; }
-    bool wantDumpVoxelsOnMove() const { return _dumpVoxelsOnMove; }
-    bool wantDisplayVoxelStats() const { return _displayVoxelStats; }
-
-    VoxelTree& getServerTree() { return _serverTree; }
-    JurisdictionMap* getJurisdiction() { return _jurisdiction; }
-    
-    int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; }
-    bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; }
-    EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; }
-    int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); }
-    
-    static VoxelServer* GetInstance() { return _theInstance; }
-    
-    bool isInitialLoadComplete() const { return (_voxelPersistThread) ? _voxelPersistThread->isInitialLoadComplete() : true; }
-    time_t* getLoadCompleted() { return (_voxelPersistThread) ? _voxelPersistThread->getLoadCompleted() : NULL; }
-    uint64_t getLoadElapsedTime() const { return (_voxelPersistThread) ? _voxelPersistThread->getLoadElapsedTime() : 0; }
-public slots:
-    /// runs the voxel server assignment
-    void run();
-    
-    void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);
-private:
-    int _argc;
-    const char** _argv;
-    char** _parsedArgV;
-
-    char _voxelPersistFilename[MAX_FILENAME_LENGTH];
-    int _packetsPerClientPerInterval;
-    VoxelTree _serverTree; // this IS a reaveraging tree 
-    bool _wantVoxelPersist;
-    bool _wantLocalDomain;
-    bool _debugVoxelSending;
-    bool _shouldShowAnimationDebug;
-    bool _displayVoxelStats;
-    bool _debugVoxelReceiving;
-    bool _sendEnvironments;
-    bool _sendMinimalEnvironment;
-    bool _dumpVoxelsOnMove;
-    bool _verboseDebug;
-    JurisdictionMap* _jurisdiction;
-    JurisdictionSender* _jurisdictionSender;
-    VoxelServerPacketProcessor* _voxelServerPacketProcessor;
-    VoxelPersistThread* _voxelPersistThread;
-    EnvironmentData _environmentData[3];
-    
-    NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed
-    
-    void parsePayload();
-
-    void initMongoose(int port);
-
-    static int civetwebRequestHandler(struct mg_connection *connection);
-    static VoxelServer* _theInstance;
-    
-    time_t _started;
-    uint64_t _startedUSecs;
-};
-
-#endif // __voxel_server__VoxelServer__
diff --git a/libraries/voxel-server-library/src/VoxelServerConsts.h b/libraries/voxel-server-library/src/VoxelServerConsts.h
deleted file mode 100644
index 216ecd8f80..0000000000
--- a/libraries/voxel-server-library/src/VoxelServerConsts.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//  VoxelServerConsts.h
-//  voxel-server
-//
-//  Created by Brad Hefta-Gaub on 8/21/13
-//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
-//
-//
-
-#ifndef __voxel_server__VoxelServerConsts__
-#define __voxel_server__VoxelServerConsts__
-
-#include 
-#include  // for MAX_PACKET_SIZE
-#include 
-#include 
-
-#include "VoxelServerPacketProcessor.h"
-
-
-const int MAX_FILENAME_LENGTH = 1024;
-const int INTERVALS_PER_SECOND = 60;
-const int VOXEL_SEND_INTERVAL_USECS = (1000 * 1000)/INTERVALS_PER_SECOND;
-const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
-const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
-
-extern const char* LOCAL_VOXELS_PERSIST_FILE;
-extern const char* VOXELS_PERSIST_FILE;
-
-#endif // __voxel_server__VoxelServerConsts__
diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp
deleted file mode 100644
index 3a0bc70f42..0000000000
--- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-//
-//  VoxelServerPacketProcessor.cpp
-//  voxel-server
-//
-//  Created by Brad Hefta-Gaub on 8/21/13
-//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
-//
-//  Threaded or non-threaded network packet processor for the voxel-server
-//
-
-#include 
-#include 
-
-#include "VoxelServer.h"
-#include "VoxelServerConsts.h"
-#include "VoxelServerPacketProcessor.h"
-
-static QUuid DEFAULT_NODE_ID_REF;
-
-VoxelServerPacketProcessor::VoxelServerPacketProcessor(VoxelServer* myServer) :
-    _myServer(myServer),
-    _receivedPacketCount(0),
-    _totalTransitTime(0),
-    _totalProcessTime(0),
-    _totalLockWaitTime(0),
-    _totalVoxelsInPacket(0),
-    _totalPackets(0)
-{
-}
-
-void VoxelServerPacketProcessor::resetStats() {
-    _totalTransitTime = 0;
-    _totalProcessTime = 0;
-    _totalLockWaitTime = 0;
-    _totalVoxelsInPacket = 0;
-    _totalPackets = 0;
-    
-    _singleSenderStats.clear();
-}
-
-
-void VoxelServerPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr,
-                                               unsigned char* packetData, ssize_t packetLength) {
-
-    bool debugProcessPacket = _myServer->wantsVerboseDebug();
-    
-    if (debugProcessPacket) {
-        printf("VoxelServerPacketProcessor::processPacket() packetData=%p packetLength=%ld\n", packetData, packetLength);
-    }
-
-    int numBytesPacketHeader = numBytesForPacketHeader(packetData);
-    
-    if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) {
-        bool destructive = (packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
-        PerformanceWarning warn(_myServer->wantShowAnimationDebug(),
-                                destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
-                                _myServer->wantShowAnimationDebug());
-
-        _receivedPacketCount++;
-        
-        unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
-        uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence))));
-        uint64_t arrivedAt = usecTimestampNow();
-        uint64_t transitTime = arrivedAt - sentAt;
-        int voxelsInPacket = 0;
-        uint64_t processTime = 0;
-        uint64_t lockWaitTime = 0;
-        
-        if (_myServer->wantShowAnimationDebug() || _myServer->wantsDebugVoxelReceiving()) {
-            printf("PROCESSING THREAD: got %s - %d command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n",
-                destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
-                _receivedPacketCount, packetLength, sequence, transitTime);
-        }
-        int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt);
-        unsigned char* voxelData = (unsigned char*)&packetData[atByte];
-        while (atByte < packetLength) {
-            int maxSize = packetLength - atByte;
-
-            if (debugProcessPacket) {
-                printf("VoxelServerPacketProcessor::processPacket() %s packetData=%p packetLength=%ld voxelData=%p atByte=%d maxSize=%d\n",
-                    destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
-                    packetData, packetLength, voxelData, atByte, maxSize);
-            }
-
-            int octets = numberOfThreeBitSectionsInCode(voxelData, maxSize);
-            
-            if (octets == OVERFLOWED_OCTCODE_BUFFER) {
-                printf("WARNING! Got voxel edit record that would overflow buffer in numberOfThreeBitSectionsInCode(), ");
-                printf("bailing processing of packet!\n");
-                break;
-            }
-            
-            const int COLOR_SIZE_IN_BYTES = 3;
-            int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES;
-            int voxelCodeSize = bytesRequiredForCodeLength(octets);
-
-            if (atByte + voxelDataSize <= packetLength) {
-                if (_myServer->wantShowAnimationDebug()) {
-                    int red   = voxelData[voxelCodeSize + RED_INDEX];
-                    int green = voxelData[voxelCodeSize + GREEN_INDEX];
-                    int blue  = voxelData[voxelCodeSize + BLUE_INDEX];
-
-                    float* vertices = firstVertexForCode(voxelData);
-                    printf("inserting voxel: %f,%f,%f r=%d,g=%d,b=%d\n", vertices[0], vertices[1], vertices[2], red, green, blue);
-                    delete[] vertices;
-                }
-
-                uint64_t startLock = usecTimestampNow();
-                _myServer->getServerTree().lockForWrite();
-                uint64_t startProcess = usecTimestampNow();
-                _myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive);
-                _myServer->getServerTree().unlock();
-                uint64_t endProcess = usecTimestampNow();
-                
-                voxelsInPacket++;
-
-                uint64_t thisProcessTime = endProcess - startProcess;
-                uint64_t thisLockWaitTime = startProcess - startLock;
-
-                processTime += thisProcessTime;
-                lockWaitTime += thisLockWaitTime;
-
-                // skip to next voxel edit record in the packet
-                voxelData += voxelDataSize;
-                atByte += voxelDataSize;
-            } else {
-                printf("WARNING! Got voxel edit record that would overflow buffer, bailing processing of packet!\n");
-                break;
-            }
-        }
-
-        if (debugProcessPacket) {
-            printf("VoxelServerPacketProcessor::processPacket() DONE LOOPING FOR %s packetData=%p packetLength=%ld voxelData=%p atByte=%d\n",
-                destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
-                packetData, packetLength, voxelData, atByte);
-        }
-
-        // Make sure our Node and NodeList knows we've heard from this node.
-        Node* senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
-        QUuid& nodeUUID = DEFAULT_NODE_ID_REF;
-        if (senderNode) {
-            senderNode->setLastHeardMicrostamp(usecTimestampNow());
-            nodeUUID = senderNode->getUUID();
-            if (debugProcessPacket) {
-                qDebug() << "sender has uuid=" << nodeUUID << "\n";
-            }
-        } else {
-            if (debugProcessPacket) {
-                qDebug() << "sender has no known nodeUUID.\n";
-            }
-        }
-        trackInboundPackets(nodeUUID, sequence, transitTime, voxelsInPacket, processTime, lockWaitTime);
-
-    } else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) {
-
-        _receivedPacketCount++;
-        
-        unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
-        uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence))));
-        uint64_t arrivedAt = usecTimestampNow();
-        uint64_t transitTime = arrivedAt - sentAt;
-
-        if (_myServer->wantShowAnimationDebug() || _myServer->wantsDebugVoxelReceiving()) {
-            printf("PROCESSING THREAD: got PACKET_TYPE_ERASE_VOXEL - %d command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n",
-                _receivedPacketCount, packetLength, sequence, transitTime);
-        }
-
-        // Send these bits off to the VoxelTree class to process them
-        _myServer->getServerTree().lockForWrite();
-        _myServer->getServerTree().processRemoveOctreeElementsBitstream((unsigned char*)packetData, packetLength);
-        _myServer->getServerTree().unlock();
-
-        // Make sure our Node and NodeList knows we've heard from this node.
-        Node* node = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
-        if (node) {
-            node->setLastHeardMicrostamp(usecTimestampNow());
-        }
-    } else {
-        printf("unknown packet ignored... packetData[0]=%c\n", packetData[0]);
-    }
-}
-
-void VoxelServerPacketProcessor::trackInboundPackets(const QUuid& nodeUUID, int sequence, uint64_t transitTime, 
-            int voxelsInPacket, uint64_t processTime, uint64_t lockWaitTime) {
-            
-    _totalTransitTime += transitTime;
-    _totalProcessTime += processTime;
-    _totalLockWaitTime += lockWaitTime;
-    _totalVoxelsInPacket += voxelsInPacket;
-    _totalPackets++;
-    
-    // find the individual senders stats and track them there too...
-    // see if this is the first we've heard of this node...
-    if (_singleSenderStats.find(nodeUUID) == _singleSenderStats.end()) {
-        SingleSenderStats stats;
-
-        stats._totalTransitTime += transitTime;
-        stats._totalProcessTime += processTime;
-        stats._totalLockWaitTime += lockWaitTime;
-        stats._totalVoxelsInPacket += voxelsInPacket;
-        stats._totalPackets++;
-
-        _singleSenderStats[nodeUUID] = stats;
-    } else {
-        SingleSenderStats& stats = _singleSenderStats[nodeUUID];
-        stats._totalTransitTime += transitTime;
-        stats._totalProcessTime += processTime;
-        stats._totalLockWaitTime += lockWaitTime;
-        stats._totalVoxelsInPacket += voxelsInPacket;
-        stats._totalPackets++;
-    }
-}
-
-
-SingleSenderStats::SingleSenderStats() {
-    _totalTransitTime = 0; 
-    _totalProcessTime = 0;
-    _totalLockWaitTime = 0;
-    _totalVoxelsInPacket = 0;
-    _totalPackets = 0;
-}
-
-
diff --git a/libraries/voxel-server/CMakeLists.txt b/libraries/voxel-server/CMakeLists.txt
new file mode 100644
index 0000000000..0db5fc5575
--- /dev/null
+++ b/libraries/voxel-server/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(ROOT_DIR ../..)
+set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
+
+# setup for find modules
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
+
+set(TARGET_NAME voxel-server)
+
+find_package(Qt5Widgets REQUIRED)
+
+include(${MACRO_DIR}/SetupHifiLibrary.cmake)
+
+setup_hifi_library(${TARGET_NAME} ${OPTIONAL_SRCS})
+
+qt5_use_modules(${TARGET_NAME} Widgets)
+
+include(${MACRO_DIR}/IncludeGLM.cmake)
+include_glm(${TARGET_NAME} ${ROOT_DIR})
+
+# link ZLIB
+find_package(ZLIB)
+include_directories(${ZLIB_INCLUDE_DIRS})
+target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
+
+# link in the shared library
+include(${MACRO_DIR}/LinkHifiLibrary.cmake)
+link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
+
+# link in the hifi octree library
+link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
+link_hifi_library(octree-server ${TARGET_NAME} ${ROOT_DIR})
+link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
diff --git a/libraries/voxel-server/src/VoxelNodeData.h b/libraries/voxel-server/src/VoxelNodeData.h
new file mode 100644
index 0000000000..92a5230567
--- /dev/null
+++ b/libraries/voxel-server/src/VoxelNodeData.h
@@ -0,0 +1,21 @@
+//
+//  VoxelNodeData.h
+//  hifi
+//
+//  Created by Stephen Birarda on 3/21/13.
+//
+//
+
+#ifndef __hifi__VoxelNodeData__
+#define __hifi__VoxelNodeData__
+
+#include 
+#include 
+
+class VoxelNodeData : public OctreeQueryNode {
+public:
+    VoxelNodeData(Node* owningNode) : OctreeQueryNode(owningNode) {  };
+    virtual PACKET_TYPE getMyPacketType() const { return PACKET_TYPE_VOXEL_DATA; }
+};
+
+#endif /* defined(__hifi__VoxelNodeData__) */
diff --git a/libraries/voxel-server/src/VoxelServer.cpp b/libraries/voxel-server/src/VoxelServer.cpp
new file mode 100644
index 0000000000..4f0140d892
--- /dev/null
+++ b/libraries/voxel-server/src/VoxelServer.cpp
@@ -0,0 +1,71 @@
+//
+//  VoxelServer.cpp
+//  hifi
+//
+//  Created by Brad Hefta-Gaub on 9/16/13.
+//  Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
+//
+
+#include 
+
+#include "VoxelServer.h"
+#include "VoxelServerConsts.h"
+#include "VoxelNodeData.h"
+
+const char* VOXEL_SERVER_NAME = "Voxel";
+const char* VOXEL_SERVER_LOGGING_TARGET_NAME = "voxel-server";
+const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo";
+
+VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : OctreeServer(dataBuffer, numBytes) {
+    // nothing special to do here...
+}
+
+VoxelServer::~VoxelServer() {
+    // nothing special to do here...
+}
+
+OctreeQueryNode* VoxelServer::createOctreeQueryNode(Node* newNode) {
+    return new VoxelNodeData(newNode);
+}
+
+Octree* VoxelServer::createTree() {
+    return new VoxelTree(true);
+}
+
+bool VoxelServer::hasSpecialPacketToSend() {
+    bool shouldSendEnvironments = _sendEnvironments && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, OCTREE_SEND_INTERVAL_USECS);
+    return shouldSendEnvironments;
+}
+
+int VoxelServer::sendSpecialPacket(Node* node) {
+    int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA);
+    int envPacketLength = numBytesPacketHeader;
+    int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount();
+    
+    for (int i = 0; i < environmentsToSend; i++) {
+        envPacketLength += getEnvironmentData(i)->getBroadcastData(_tempOutputBuffer + envPacketLength);
+    }
+    
+    NodeList::getInstance()->getNodeSocket().writeDatagram((char*) _tempOutputBuffer, envPacketLength,
+                                                           node->getActiveSocket()->getAddress(),
+                                                           node->getActiveSocket()->getPort());
+    return envPacketLength;
+}
+
+
+void VoxelServer::beforeRun() {
+    // should we send environments? Default is yes, but this command line suppresses sending
+    const char* SEND_ENVIRONMENTS = "--sendEnvironments";
+    bool dontSendEnvironments =  !cmdOptionExists(_argc, _argv, SEND_ENVIRONMENTS);
+    if (dontSendEnvironments) {
+        qDebug("Sending environments suppressed...\n");
+        _sendEnvironments = false;
+    } else {
+        _sendEnvironments = true;
+        // should we send environments? Default is yes, but this command line suppresses sending
+        const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment";
+        _sendMinimalEnvironment =  cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT);
+        qDebug("Using Minimal Environment=%s\n", debug::valueOf(_sendMinimalEnvironment));
+    }
+    qDebug("Sending environments=%s\n", debug::valueOf(_sendEnvironments));
+}
diff --git a/libraries/voxel-server/src/VoxelServer.h b/libraries/voxel-server/src/VoxelServer.h
new file mode 100644
index 0000000000..e785d2f65e
--- /dev/null
+++ b/libraries/voxel-server/src/VoxelServer.h
@@ -0,0 +1,58 @@
+//
+//  VoxelServer.h
+//  voxel-server
+//
+//  Created by Brad Hefta-Gaub on 8/21/13
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+//
+
+#ifndef __voxel_server__VoxelServer__
+#define __voxel_server__VoxelServer__
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+
+
+#include "VoxelServerConsts.h"
+
+/// Handles assignments of type VoxelServer - sending voxels to various clients.
+class VoxelServer : public OctreeServer {
+public:                
+    VoxelServer(const unsigned char* dataBuffer, int numBytes);
+    ~VoxelServer();
+
+    bool wantSendEnvironments() const { return _sendEnvironments; }
+    bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; }
+    EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; }
+    int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); }
+
+    // Subclasses must implement these methods    
+    virtual OctreeQueryNode* createOctreeQueryNode(Node* newNode);
+    virtual Octree* createTree();
+    virtual unsigned char getMyNodeType() const { return NODE_TYPE_VOXEL_SERVER; }
+    virtual PACKET_TYPE getMyQueryMessageType() const { return PACKET_TYPE_VOXEL_QUERY; }
+    virtual const char* getMyServerName() const { return VOXEL_SERVER_NAME; }
+    virtual const char* getMyLoggingServerTargetName() const { return VOXEL_SERVER_LOGGING_TARGET_NAME; }
+    virtual const char* getMyDefaultPersistFilename() const { return LOCAL_VOXELS_PERSIST_FILE; }
+    
+    // subclass may implement these method
+    virtual void beforeRun();
+    virtual bool hasSpecialPacketToSend();
+    virtual int sendSpecialPacket(Node* node);
+
+
+private:
+    bool _sendEnvironments;
+    bool _sendMinimalEnvironment;
+    EnvironmentData _environmentData[3];
+    unsigned char _tempOutputBuffer[MAX_PACKET_SIZE];
+};
+
+#endif // __voxel_server__VoxelServer__
diff --git a/libraries/voxel-server/src/VoxelServerConsts.h b/libraries/voxel-server/src/VoxelServerConsts.h
new file mode 100644
index 0000000000..ce6fd86a32
--- /dev/null
+++ b/libraries/voxel-server/src/VoxelServerConsts.h
@@ -0,0 +1,18 @@
+//  VoxelServerConsts.h
+//  voxel-server
+//
+//  Created by Brad Hefta-Gaub on 8/21/13
+//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
+//
+//
+
+#ifndef __voxel_server__VoxelServerConsts__
+#define __voxel_server__VoxelServerConsts__
+
+extern const char* VOXEL_SERVER_NAME;
+extern const char* VOXEL_SERVER_LOGGING_TARGET_NAME;
+extern const char* LOCAL_VOXELS_PERSIST_FILE;
+
+const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
+
+#endif // __voxel_server__VoxelServerConsts__
diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp
index bfc42da63f..467bf7934c 100644
--- a/libraries/voxels/src/VoxelEditPacketSender.cpp
+++ b/libraries/voxels/src/VoxelEditPacketSender.cpp
@@ -137,14 +137,14 @@ void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned ch
 
                     const char* messageName;
                     switch (buffer[0]) {
-                        case PACKET_TYPE_SET_VOXEL: 
-                            messageName = "PACKET_TYPE_SET_VOXEL"; 
+                        case PACKET_TYPE_VOXEL_SET: 
+                            messageName = "PACKET_TYPE_VOXEL_SET"; 
                             break;
-                        case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: 
-                            messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE"; 
+                        case PACKET_TYPE_VOXEL_SET_DESTRUCTIVE: 
+                            messageName = "PACKET_TYPE_VOXEL_SET_DESTRUCTIVE"; 
                             break;
-                        case PACKET_TYPE_ERASE_VOXEL: 
-                            messageName = "PACKET_TYPE_ERASE_VOXEL"; 
+                        case PACKET_TYPE_VOXEL_ERASE: 
+                            messageName = "PACKET_TYPE_VOXEL_ERASE"; 
                             break;
                     }
                     printf("VoxelEditPacketSender::queuePacketToNode() queued %s - command to node bytes=%ld sequence=%d transitTimeSoFar=%llu usecs\n",
diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp
index ff722143c4..986d70665e 100644
--- a/libraries/voxels/src/VoxelTree.cpp
+++ b/libraries/voxels/src/VoxelTree.cpp
@@ -355,7 +355,7 @@ void VoxelTree::nudgeLeaf(VoxelTreeElement* element, void* extraData) {
     glm::vec3 nudge = args->nudgeVec;
 
     // delete the old element
-    args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, voxelDetails);
+    args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_VOXEL_ERASE, voxelDetails);
 
     // nudge the old element
     voxelDetails.x += nudge.x;
@@ -363,7 +363,7 @@ void VoxelTree::nudgeLeaf(VoxelTreeElement* element, void* extraData) {
     voxelDetails.z += nudge.z;
 
     // create a new voxel in its stead
-    args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE, voxelDetails);
+    args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, voxelDetails);
 }
 
 // Recurses voxel element with an operation function
@@ -638,3 +638,54 @@ void VoxelTree::readCodeColorBufferToTreeRecursion(VoxelTreeElement* node, ReadC
         node->handleSubtreeChanged(this);
     }
 }
+
+bool VoxelTree::handlesEditPacketType(PACKET_TYPE packetType) const {
+    // we handle these types of "edit" packets
+    switch (packetType) {
+        case PACKET_TYPE_VOXEL_SET:
+        case PACKET_TYPE_VOXEL_SET_DESTRUCTIVE:
+        case PACKET_TYPE_VOXEL_ERASE:
+            return true;
+    }
+    return false;
+}
+
+int VoxelTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength,
+                    unsigned char* editData, int maxLength) {
+
+    int processedBytes = 0;
+    // we handle these types of "edit" packets
+    switch (packetType) {
+        case PACKET_TYPE_VOXEL_SET:
+        case PACKET_TYPE_VOXEL_SET_DESTRUCTIVE: {
+            bool destructive = (packetType == PACKET_TYPE_VOXEL_SET_DESTRUCTIVE);
+            int octets = numberOfThreeBitSectionsInCode(editData, maxLength);
+            
+            if (octets == OVERFLOWED_OCTCODE_BUFFER) {
+                printf("WARNING! Got voxel edit record that would overflow buffer in numberOfThreeBitSectionsInCode(), ");
+                printf("bailing processing of packet!\n");
+                return processedBytes;
+            }
+
+            const int COLOR_SIZE_IN_BYTES = 3;
+            int voxelCodeSize = bytesRequiredForCodeLength(octets);
+            int voxelDataSize = voxelCodeSize + COLOR_SIZE_IN_BYTES;
+
+            if (voxelDataSize > maxLength) {
+                printf("WARNING! Got voxel edit record that would overflow buffer, bailing processing of packet!\n");
+                printf("bailing processing of packet!\n");
+                return processedBytes;
+            }
+            
+            readCodeColorBufferToTree(editData, destructive);
+            
+            return voxelDataSize;
+        } break;
+            
+        case PACKET_TYPE_VOXEL_ERASE:
+            processRemoveOctreeElementsBitstream((unsigned char*)packetData, packetLength);
+            return maxLength;
+    }
+    return processedBytes;
+}
+
diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h
index 2654663101..eae47885b2 100644
--- a/libraries/voxels/src/VoxelTree.h
+++ b/libraries/voxels/src/VoxelTree.h
@@ -53,6 +53,11 @@ public:
 
     void readCodeColorBufferToTree(const unsigned char* codeColorBuffer, bool destructive = false);
 
+    virtual bool handlesEditPacketType(PACKET_TYPE packetType) const;
+    virtual int processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength,
+                    unsigned char* editData, int maxLength);
+    void processSetVoxelsBitstream(const unsigned char* bitstream, int bufferSizeBytes);
+
 /**
 signals:
     void importSize(float x, float y, float z);