mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge pull request #1312 from ZappoMan/more_on_particle_server
First cut at basic Particle Server
This commit is contained in:
commit
0c4b66ef54
57 changed files with 1405 additions and 951 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "audio/AudioMixer.h"
|
||||
#include "avatars/AvatarMixer.h"
|
||||
#include <VoxelServer.h>
|
||||
#include <ParticleServer.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ private:
|
|||
Assignment* _staticAssignments;
|
||||
|
||||
const char* _voxelServerConfig;
|
||||
const char* _particleServerConfig;
|
||||
|
||||
bool _hasCompletedRestartHold;
|
||||
};
|
||||
|
|
|
@ -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()");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
168
libraries/octree-server/src/OctreeInboundPacketProcessor.cpp
Normal file
168
libraries/octree-server/src/OctreeInboundPacketProcessor.cpp
Normal file
|
@ -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 <PacketHeaders.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
@ -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 <map>
|
||||
|
||||
#include <ReceivedPacketProcessor.h>
|
||||
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<QUuid, SingleSenderStats>::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__
|
|
@ -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 <QDebug>
|
||||
#include <NodeList.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 <GenericThread.h>
|
||||
#include <NetworkPacket.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <Octree.h>
|
||||
|
||||
/// 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__
|
|
@ -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 <cstring>
|
||||
#include <cstdio>
|
||||
#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;
|
|
@ -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 <iostream>
|
||||
#include <NodeData.h>
|
||||
#include <VoxelPacketData.h>
|
||||
#include <VoxelQuery.h>
|
||||
#include <OctreePacketData.h>
|
||||
#include <OctreeQuery.h>
|
||||
|
||||
#include <CoverageMap.h>
|
||||
#include <VoxelConstants.h>
|
||||
#include <OctreeConstants.h>
|
||||
#include <OctreeElementBag.h>
|
||||
#include <VoxelSceneStats.h>
|
||||
#include <OctreeSceneStats.h>
|
||||
|
||||
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__) */
|
|
@ -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 <EnvironmentData.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
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);
|
45
libraries/octree-server/src/OctreeSendThread.h
Normal file
45
libraries/octree-server/src/OctreeSendThread.h
Normal file
|
@ -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 <GenericThread.h>
|
||||
#include <NetworkPacket.h>
|
||||
#include <OctreeElementBag.h>
|
||||
#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__
|
|
@ -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 <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <time.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include <Logging.h>
|
||||
#include <OctalCode.h>
|
||||
#include <NodeList.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <VoxelTree.h>
|
||||
#include "VoxelNodeData.h"
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SceneUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <JurisdictionSender.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Syssocket.h"
|
||||
#include "Systime.h"
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#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", "<html><doc>\r\n");
|
||||
mg_printf(connection, "%s", "<pre>\r\n");
|
||||
mg_printf(connection, "%s", "<b>Your Voxel Server is running... <a href='/'>[RELOAD]</a></b>\r\n");
|
||||
mg_printf(connection, "<b>Your %s Server is running... <a href='/'>[RELOAD]</a></b>\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", "<b>Voxel Packet Statistics...</b>\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, "<b>%s Outbound Packet Statistics...</b>\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", "<b>Voxel Edit Statistics... <a href='/resetStats'>[RESET]</a></b>\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, "<b>%s Edit Statistics... <a href='/resetStats'>[RESET]</a></b>\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", "<b>Current Memory Usage Statistics</b>\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<const char**>(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";
|
||||
}
|
||||
|
||||
|
98
libraries/octree-server/src/OctreeServer.h
Normal file
98
libraries/octree-server/src/OctreeServer.h
Normal file
|
@ -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 <QStringList>
|
||||
#include <QDateTime>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <EnvironmentData.h>
|
||||
|
||||
#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__
|
21
libraries/octree-server/src/OctreeServerConsts.h
Normal file
21
libraries/octree-server/src/OctreeServerConsts.h
Normal file
|
@ -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 <SharedUtil.h>
|
||||
#include <NodeList.h> // for MAX_PACKET_SIZE
|
||||
#include <JurisdictionSender.h>
|
||||
|
||||
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__
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <ReceivedPacketProcessor.h>
|
||||
#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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
35
libraries/particle-server/CMakeLists.txt
Normal file
35
libraries/particle-server/CMakeLists.txt
Normal file
|
@ -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})
|
||||
|
22
libraries/particle-server/src/ParticleNodeData.h
Normal file
22
libraries/particle-server/src/ParticleNodeData.h
Normal file
|
@ -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 <OctreeQueryNode.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
class ParticleNodeData : public OctreeQueryNode {
|
||||
public:
|
||||
ParticleNodeData(Node* owningNode) : OctreeQueryNode(owningNode) { };
|
||||
virtual PACKET_TYPE getMyPacketType() const { return PACKET_TYPE_PARTICLE_DATA; }
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__ParticleNodeData__) */
|
37
libraries/particle-server/src/ParticleServer.cpp
Normal file
37
libraries/particle-server/src/ParticleServer.cpp
Normal file
|
@ -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 <ParticleTree.h>
|
||||
|
||||
#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...
|
||||
}
|
38
libraries/particle-server/src/ParticleServer.h
Normal file
38
libraries/particle-server/src/ParticleServer.h
Normal file
|
@ -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 <OctreeServer.h>
|
||||
|
||||
#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__
|
16
libraries/particle-server/src/ParticleServerConsts.h
Normal file
16
libraries/particle-server/src/ParticleServerConsts.h
Normal file
|
@ -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__
|
28
libraries/particles/CMakeLists.txt
Normal file
28
libraries/particles/CMakeLists.txt
Normal file
|
@ -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})
|
19
libraries/particles/src/ParticleTree.cpp
Normal file
19
libraries/particles/src/ParticleTree.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
24
libraries/particles/src/ParticleTree.h
Normal file
24
libraries/particles/src/ParticleTree.h
Normal file
|
@ -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 <Octree.h>
|
||||
#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__) */
|
62
libraries/particles/src/ParticleTreeElement.cpp
Normal file
62
libraries/particles/src/ParticleTreeElement.cpp
Normal file
|
@ -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 <QtCore/QDebug>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
45
libraries/particles/src/ParticleTreeElement.h
Normal file
45
libraries/particles/src/ParticleTreeElement.h
Normal file
|
@ -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 <OctreeElement.h>
|
||||
|
||||
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__) */
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
AvatarMixerType,
|
||||
AgentType,
|
||||
VoxelServerType,
|
||||
ParticleServerType,
|
||||
AllTypes
|
||||
};
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 <NodeList.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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 <NodeList.h>
|
||||
|
||||
/// 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__
|
|
@ -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 <GenericThread.h>
|
||||
#include <NetworkPacket.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <OctreeElementBag.h>
|
||||
#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__
|
|
@ -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 <QStringList>
|
||||
#include <QDateTime>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <EnvironmentData.h>
|
||||
|
||||
#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__
|
|
@ -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 <SharedUtil.h>
|
||||
#include <NodeList.h> // for MAX_PACKET_SIZE
|
||||
#include <JurisdictionSender.h>
|
||||
#include <VoxelTree.h>
|
||||
|
||||
#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__
|
|
@ -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 <PacketHeaders.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
34
libraries/voxel-server/CMakeLists.txt
Normal file
34
libraries/voxel-server/CMakeLists.txt
Normal file
|
@ -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})
|
21
libraries/voxel-server/src/VoxelNodeData.h
Normal file
21
libraries/voxel-server/src/VoxelNodeData.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// VoxelNodeData.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 3/21/13.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __hifi__VoxelNodeData__
|
||||
#define __hifi__VoxelNodeData__
|
||||
|
||||
#include <OctreeQueryNode.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
class VoxelNodeData : public OctreeQueryNode {
|
||||
public:
|
||||
VoxelNodeData(Node* owningNode) : OctreeQueryNode(owningNode) { };
|
||||
virtual PACKET_TYPE getMyPacketType() const { return PACKET_TYPE_VOXEL_DATA; }
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__VoxelNodeData__) */
|
71
libraries/voxel-server/src/VoxelServer.cpp
Normal file
71
libraries/voxel-server/src/VoxelServer.cpp
Normal file
|
@ -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 <VoxelTree.h>
|
||||
|
||||
#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));
|
||||
}
|
58
libraries/voxel-server/src/VoxelServer.h
Normal file
58
libraries/voxel-server/src/VoxelServer.h
Normal file
|
@ -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 <QStringList>
|
||||
#include <QDateTime>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
#include <EnvironmentData.h>
|
||||
|
||||
#include <OctreeServer.h>
|
||||
|
||||
|
||||
#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__
|
18
libraries/voxel-server/src/VoxelServerConsts.h
Normal file
18
libraries/voxel-server/src/VoxelServerConsts.h
Normal file
|
@ -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__
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue