mirror of
https://github.com/overte-org/overte.git
synced 2025-07-24 00:43:49 +02:00
Merge branch 'master' of ssh://github.com/highfidelity/hifi into avatar-interaction
This commit is contained in:
commit
afa1134282
29 changed files with 301 additions and 228 deletions
|
@ -807,7 +807,7 @@ AnimationServer::AnimationServer(int &argc, char **argv) :
|
||||||
|
|
||||||
pthread_create(&::animateVoxelThread, NULL, animateVoxels, NULL);
|
pthread_create(&::animateVoxelThread, NULL, animateVoxels, NULL);
|
||||||
|
|
||||||
NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_VOXEL_SERVER, 1);
|
NodeList::getInstance()->addNodeTypeToInterestSet(NODE_TYPE_VOXEL_SERVER);
|
||||||
|
|
||||||
QTimer* domainServerTimer = new QTimer(this);
|
QTimer* domainServerTimer = new QTimer(this);
|
||||||
connect(domainServerTimer, SIGNAL(timeout()), nodeList, SLOT(sendDomainServerCheckIn()));
|
connect(domainServerTimer, SIGNAL(timeout()), nodeList, SLOT(sendDomainServerCheckIn()));
|
||||||
|
|
|
@ -52,13 +52,7 @@ void Agent::run() {
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
nodeList->setOwnerType(NODE_TYPE_AGENT);
|
nodeList->setOwnerType(NODE_TYPE_AGENT);
|
||||||
|
|
||||||
// XXXBHG - this seems less than ideal. There might be classes (like jurisdiction listeners, that need access to
|
nodeList->addSetOfNodeTypesToNodeInterestSet(QSet<NODE_TYPE>() << NODE_TYPE_AUDIO_MIXER << NODE_TYPE_AVATAR_MIXER);
|
||||||
// other node types, but for them to get access to those node types, we have to add them here. It seems like
|
|
||||||
// NodeList should support adding types of interest
|
|
||||||
const NODE_TYPE AGENT_NODE_TYPES_OF_INTEREST[] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_PARTICLE_SERVER,
|
|
||||||
NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER };
|
|
||||||
|
|
||||||
nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST));
|
|
||||||
|
|
||||||
// figure out the URL for the script for this agent assignment
|
// figure out the URL for the script for this agent assignment
|
||||||
QString scriptURLString("http://%1:8080/assignment/%2");
|
QString scriptURLString("http://%1:8080/assignment/%2");
|
||||||
|
|
|
@ -241,8 +241,7 @@ void AudioMixer::run() {
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
|
||||||
const char AUDIO_MIXER_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_AGENT, NODE_TYPE_AUDIO_INJECTOR };
|
nodeList->addNodeTypeToInterestSet(NODE_TYPE_AGENT);
|
||||||
nodeList->setNodeTypesOfInterest(AUDIO_MIXER_NODE_TYPES_OF_INTEREST, sizeof(AUDIO_MIXER_NODE_TYPES_OF_INTEREST));
|
|
||||||
|
|
||||||
nodeList->linkedDataCreateCallback = attachNewBufferToNode;
|
nodeList->linkedDataCreateCallback = attachNewBufferToNode;
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ void AvatarMixer::run() {
|
||||||
commonInit(AVATAR_MIXER_LOGGING_NAME, NODE_TYPE_AVATAR_MIXER);
|
commonInit(AVATAR_MIXER_LOGGING_NAME, NODE_TYPE_AVATAR_MIXER);
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
nodeList->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1);
|
nodeList->addNodeTypeToInterestSet(NODE_TYPE_AGENT);
|
||||||
|
|
||||||
nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
|
nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,8 @@ function vMinus(a, b) {
|
||||||
|
|
||||||
// First, load two percussion sounds to be used on the sticks
|
// First, load two percussion sounds to be used on the sticks
|
||||||
|
|
||||||
var drum1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/MusicalInstruments/drums/snare.raw");
|
var drum1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Drums/RackTomHi.raw");
|
||||||
var drum2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/MusicalInstruments/drums/snare.raw");
|
var drum2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Drums/RackTomLo.raw");
|
||||||
|
|
||||||
// State Machine:
|
// State Machine:
|
||||||
// 0 = not triggered
|
// 0 = not triggered
|
||||||
|
|
|
@ -42,7 +42,7 @@ Voxels.setVoxel(position.x, 0, position.z, 0.5, 0, 0, 255);
|
||||||
|
|
||||||
var totalParticles = 0;
|
var totalParticles = 0;
|
||||||
function makeFountain() {
|
function makeFountain() {
|
||||||
if (Math.random() < 0.06) {
|
if (Math.random() < 0.10) {
|
||||||
//print("Made particle!\n");
|
//print("Made particle!\n");
|
||||||
var properties = {
|
var properties = {
|
||||||
position: position,
|
position: position,
|
||||||
|
@ -51,9 +51,9 @@ function makeFountain() {
|
||||||
velocity: { x: (Math.random() * 1.0 - 0.5),
|
velocity: { x: (Math.random() * 1.0 - 0.5),
|
||||||
y: (1.0 + (Math.random() * 2.0)),
|
y: (1.0 + (Math.random() * 2.0)),
|
||||||
z: (Math.random() * 1.0 - 0.5) },
|
z: (Math.random() * 1.0 - 0.5) },
|
||||||
gravity: { x: 0, y: -0.5, z: 0 },
|
gravity: { x: 0, y: -0.1, z: 0 },
|
||||||
damping: 0.25,
|
damping: 0.25,
|
||||||
lifetime: 2
|
lifetime: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Particles.addParticle(properties);
|
Particles.addParticle(properties);
|
||||||
|
|
|
@ -134,8 +134,10 @@ function checkControllerSide(whichSide) {
|
||||||
gravity: { x: 0, y: 0, z: 0},
|
gravity: { x: 0, y: 0, z: 0},
|
||||||
inHand: true,
|
inHand: true,
|
||||||
radius: 0.05,
|
radius: 0.05,
|
||||||
|
damping: 0.999,
|
||||||
color: { red: 255, green: 0, blue: 0 },
|
color: { red: 255, green: 0, blue: 0 },
|
||||||
lifetime: 10 // 10 seconds
|
|
||||||
|
lifetime: 10 // 10 seconds - same as default, not needed but here as an example
|
||||||
};
|
};
|
||||||
|
|
||||||
newParticle = Particles.addParticle(properties);
|
newParticle = Particles.addParticle(properties);
|
||||||
|
|
|
@ -108,6 +108,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
QApplication(argc, argv),
|
QApplication(argc, argv),
|
||||||
_window(new QMainWindow(desktop())),
|
_window(new QMainWindow(desktop())),
|
||||||
_glWidget(new GLCanvas()),
|
_glWidget(new GLCanvas()),
|
||||||
|
_nodeThread(new QThread(this)),
|
||||||
|
_datagramProcessor(),
|
||||||
_frameCount(0),
|
_frameCount(0),
|
||||||
_fps(120.0f),
|
_fps(120.0f),
|
||||||
_justStarted(true),
|
_justStarted(true),
|
||||||
|
@ -145,10 +147,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_voxelHideShowThread(&_voxels),
|
_voxelHideShowThread(&_voxels),
|
||||||
_voxelEditSender(this),
|
_voxelEditSender(this),
|
||||||
_particleEditSender(this),
|
_particleEditSender(this),
|
||||||
_packetCount(0),
|
|
||||||
_packetsPerSecond(0),
|
_packetsPerSecond(0),
|
||||||
_bytesPerSecond(0),
|
_bytesPerSecond(0),
|
||||||
_bytesCount(0),
|
|
||||||
_recentMaxPackets(0),
|
_recentMaxPackets(0),
|
||||||
_resetRecentMaxPacketsSoon(true),
|
_resetRecentMaxPacketsSoon(true),
|
||||||
_swatch(NULL),
|
_swatch(NULL),
|
||||||
|
@ -174,10 +174,20 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
listenPort = atoi(portStr);
|
listenPort = atoi(portStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start the nodeThread so its event loop is running
|
||||||
|
_nodeThread->start();
|
||||||
|
|
||||||
|
// make sure the node thread is given highest priority
|
||||||
|
_nodeThread->setPriority(QThread::TimeCriticalPriority);
|
||||||
|
|
||||||
|
// put the NodeList and datagram processing on the node thread
|
||||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort);
|
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort);
|
||||||
|
|
||||||
// connect our processDatagrams slot to the QUDPSocket readyRead() signal
|
nodeList->moveToThread(_nodeThread);
|
||||||
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(processDatagrams()));
|
_datagramProcessor.moveToThread(_nodeThread);
|
||||||
|
|
||||||
|
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
|
||||||
|
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), &_datagramProcessor, SLOT(processDatagrams()));
|
||||||
|
|
||||||
// put the audio processing on a separate thread
|
// put the audio processing on a separate thread
|
||||||
QThread* audioThread = new QThread(this);
|
QThread* audioThread = new QThread(this);
|
||||||
|
@ -221,12 +231,14 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// tell the NodeList instance who to tell the domain server we care about
|
// tell the NodeList instance who to tell the domain server we care about
|
||||||
const char nodeTypesOfInterest[] = {NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER, NODE_TYPE_VOXEL_SERVER,
|
nodeList->addSetOfNodeTypesToNodeInterestSet(QSet<NODE_TYPE>() << NODE_TYPE_AUDIO_MIXER << NODE_TYPE_AVATAR_MIXER
|
||||||
NODE_TYPE_PARTICLE_SERVER, NODE_TYPE_METAVOXEL_SERVER};
|
<< NODE_TYPE_VOXEL_SERVER << NODE_TYPE_PARTICLE_SERVER
|
||||||
nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
|
<< NODE_TYPE_METAVOXEL_SERVER);
|
||||||
|
|
||||||
QTimer* silentNodeTimer = new QTimer(this);
|
// move the silentNodeTimer to the _nodeThread
|
||||||
|
QTimer* silentNodeTimer = new QTimer();
|
||||||
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
||||||
|
silentNodeTimer->moveToThread(_nodeThread);
|
||||||
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
|
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
|
||||||
|
|
||||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||||
|
@ -274,10 +286,32 @@ Application::~Application() {
|
||||||
// make sure we don't call the idle timer any more
|
// make sure we don't call the idle timer any more
|
||||||
delete idleTimer;
|
delete idleTimer;
|
||||||
|
|
||||||
|
Menu::getInstance()->saveSettings();
|
||||||
|
|
||||||
|
_rearMirrorTools->saveSettings(_settings);
|
||||||
|
_settings->sync();
|
||||||
|
|
||||||
|
// let the avatar mixer know we're out
|
||||||
|
NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
|
||||||
|
|
||||||
|
// ask the datagram processing thread to quit and wait until it is done
|
||||||
|
_nodeThread->quit();
|
||||||
|
_nodeThread->wait();
|
||||||
|
|
||||||
// ask the audio thread to quit and wait until it is done
|
// ask the audio thread to quit and wait until it is done
|
||||||
_audio.thread()->quit();
|
_audio.thread()->quit();
|
||||||
_audio.thread()->wait();
|
_audio.thread()->wait();
|
||||||
|
|
||||||
|
_voxelProcessor.terminate();
|
||||||
|
_voxelHideShowThread.terminate();
|
||||||
|
_voxelEditSender.terminate();
|
||||||
|
_particleEditSender.terminate();
|
||||||
|
if (_persistThread) {
|
||||||
|
_persistThread->terminate();
|
||||||
|
_persistThread->deleteLater();
|
||||||
|
_persistThread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
storeSizeAndPosition();
|
storeSizeAndPosition();
|
||||||
saveScripts();
|
saveScripts();
|
||||||
_sharedVoxelSystem.changeTree(new VoxelTree);
|
_sharedVoxelSystem.changeTree(new VoxelTree);
|
||||||
|
@ -361,9 +395,6 @@ void Application::initializeGL() {
|
||||||
qDebug("Voxel parsing thread created.");
|
qDebug("Voxel parsing thread created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// call terminate before exiting
|
|
||||||
connect(this, SIGNAL(aboutToQuit()), SLOT(terminate()));
|
|
||||||
|
|
||||||
// call our timer function every second
|
// call our timer function every second
|
||||||
QTimer* timer = new QTimer(this);
|
QTimer* timer = new QTimer(this);
|
||||||
connect(timer, SIGNAL(timeout()), SLOT(timer()));
|
connect(timer, SIGNAL(timeout()), SLOT(timer()));
|
||||||
|
@ -1312,11 +1343,12 @@ void Application::timer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
_fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
||||||
_packetsPerSecond = (float)_packetCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
|
||||||
_bytesPerSecond = (float)_bytesCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
_packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
||||||
|
_bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
|
||||||
_frameCount = 0;
|
_frameCount = 0;
|
||||||
_packetCount = 0;
|
|
||||||
_bytesCount = 0;
|
_datagramProcessor.resetCounters();
|
||||||
|
|
||||||
gettimeofday(&_timerStart, NULL);
|
gettimeofday(&_timerStart, NULL);
|
||||||
|
|
||||||
|
@ -1395,28 +1427,6 @@ void Application::idle() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::terminate() {
|
|
||||||
// Close serial port
|
|
||||||
// close(serial_fd);
|
|
||||||
|
|
||||||
Menu::getInstance()->saveSettings();
|
|
||||||
_rearMirrorTools->saveSettings(_settings);
|
|
||||||
_settings->sync();
|
|
||||||
|
|
||||||
// let the avatar mixer know we're out
|
|
||||||
NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
|
|
||||||
|
|
||||||
_voxelProcessor.terminate();
|
|
||||||
_voxelHideShowThread.terminate();
|
|
||||||
_voxelEditSender.terminate();
|
|
||||||
_particleEditSender.terminate();
|
|
||||||
if (_persistThread) {
|
|
||||||
_persistThread->terminate();
|
|
||||||
_persistThread->deleteLater();
|
|
||||||
_persistThread = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::checkBandwidthMeterClick() {
|
void Application::checkBandwidthMeterClick() {
|
||||||
// ... to be called upon button release
|
// ... to be called upon button release
|
||||||
|
|
||||||
|
@ -1998,16 +2008,10 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3&
|
||||||
_viewFrustum.computePickRay(0.5f, 0.5f, rayOrigin, rayDirection);
|
_viewFrustum.computePickRay(0.5f, 0.5f, rayOrigin, rayDirection);
|
||||||
lookAtSpot = rayOrigin + rayDirection * FAR_AWAY_STARE;
|
lookAtSpot = rayOrigin + rayDirection * FAR_AWAY_STARE;
|
||||||
|
|
||||||
} else if (!_lookatTargetAvatar) {
|
|
||||||
if (_isHoverVoxel) {
|
|
||||||
// Look at the hovered voxel
|
|
||||||
lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Just look in direction of the mouse ray
|
// just look in direction of the mouse ray
|
||||||
lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE;
|
lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (_faceshift.isActive()) {
|
if (_faceshift.isActive()) {
|
||||||
// deflect using Faceshift gaze data
|
// deflect using Faceshift gaze data
|
||||||
glm::vec3 origin = _myAvatar.getHead().calculateAverageEyePosition();
|
glm::vec3 origin = _myAvatar.getHead().calculateAverageEyePosition();
|
||||||
|
@ -2862,10 +2866,10 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
||||||
|
|
||||||
if (!selfAvatarOnly) {
|
if (!selfAvatarOnly) {
|
||||||
// draw a red sphere
|
// draw a red sphere
|
||||||
float sphereRadius = 0.25f;
|
float originSphereRadius = 0.05f;
|
||||||
glColor3f(1,0,0);
|
glColor3f(1,0,0);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glutSolidSphere(sphereRadius, 15, 15);
|
glutSolidSphere(originSphereRadius, 15, 15);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
// disable specular lighting for ground and voxels
|
// disable specular lighting for ground and voxels
|
||||||
|
@ -4052,93 +4056,6 @@ int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLen
|
||||||
return statsMessageLength;
|
return statsMessageLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive packets from other nodes/servers and decide what to do with them!
|
|
||||||
void Application::processDatagrams() {
|
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
|
||||||
"Application::networkReceive()");
|
|
||||||
|
|
||||||
HifiSockAddr senderSockAddr;
|
|
||||||
ssize_t bytesReceived;
|
|
||||||
|
|
||||||
while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams() &&
|
|
||||||
(bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) _incomingPacket,
|
|
||||||
MAX_PACKET_SIZE,
|
|
||||||
senderSockAddr.getAddressPointer(),
|
|
||||||
senderSockAddr.getPortPointer()))) {
|
|
||||||
|
|
||||||
_packetCount++;
|
|
||||||
_bytesCount += bytesReceived;
|
|
||||||
|
|
||||||
if (packetVersionMatch(_incomingPacket)) {
|
|
||||||
// only process this packet if we have a match on the packet version
|
|
||||||
switch (_incomingPacket[0]) {
|
|
||||||
case PACKET_TYPE_TRANSMITTER_DATA_V2:
|
|
||||||
// V2 = IOS transmitter app
|
|
||||||
_myTransmitter.processIncomingData(_incomingPacket, bytesReceived);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case PACKET_TYPE_MIXED_AUDIO:
|
|
||||||
QMetaObject::invokeMethod(&_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection,
|
|
||||||
Q_ARG(QByteArray, QByteArray((char*) _incomingPacket, bytesReceived)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PACKET_TYPE_PARTICLE_ADD_RESPONSE:
|
|
||||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
|
||||||
Particle::handleAddParticleResponse(_incomingPacket, bytesReceived);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PACKET_TYPE_PARTICLE_DATA:
|
|
||||||
case PACKET_TYPE_PARTICLE_ERASE:
|
|
||||||
case PACKET_TYPE_VOXEL_DATA:
|
|
||||||
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()");
|
|
||||||
|
|
||||||
bool wantExtraDebugging = getLogger()->extraDebugging();
|
|
||||||
if (wantExtraDebugging && _incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) {
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(_incomingPacket);
|
|
||||||
unsigned char* dataAt = _incomingPacket + numBytesPacketHeader;
|
|
||||||
dataAt += sizeof(VOXEL_PACKET_FLAGS);
|
|
||||||
VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt);
|
|
||||||
dataAt += sizeof(VOXEL_PACKET_SEQUENCE);
|
|
||||||
VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt);
|
|
||||||
dataAt += sizeof(VOXEL_PACKET_SENT_TIME);
|
|
||||||
VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
|
|
||||||
int flightTime = arrivedAt - sentAt;
|
|
||||||
|
|
||||||
printf("got PACKET_TYPE_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add this packet to our list of voxel packets and process them on the voxel processing
|
|
||||||
_voxelProcessor.queueReceivedPacket(senderSockAddr, _incomingPacket, bytesReceived);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PACKET_TYPE_METAVOXEL_DATA:
|
|
||||||
_metavoxels.processData(QByteArray((const char*) _incomingPacket, bytesReceived),
|
|
||||||
senderSockAddr);
|
|
||||||
break;
|
|
||||||
case PACKET_TYPE_BULK_AVATAR_DATA:
|
|
||||||
NodeList::getInstance()->processBulkNodeData(senderSockAddr,
|
|
||||||
_incomingPacket,
|
|
||||||
bytesReceived);
|
|
||||||
getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived);
|
|
||||||
break;
|
|
||||||
case PACKET_TYPE_DATA_SERVER_GET:
|
|
||||||
case PACKET_TYPE_DATA_SERVER_PUT:
|
|
||||||
case PACKET_TYPE_DATA_SERVER_SEND:
|
|
||||||
case PACKET_TYPE_DATA_SERVER_CONFIRM:
|
|
||||||
DataServerClient::processMessageFromDataServer(_incomingPacket, bytesReceived);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
NodeList::getInstance()->processNodeData(senderSockAddr, _incomingPacket, bytesReceived);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::packetSentNotification(ssize_t length) {
|
void Application::packetSentNotification(ssize_t length) {
|
||||||
_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(length);
|
_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "BandwidthMeter.h"
|
#include "BandwidthMeter.h"
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
#include "Cloud.h"
|
#include "Cloud.h"
|
||||||
|
#include "DatagramProcessor.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
#include "GLCanvas.h"
|
#include "GLCanvas.h"
|
||||||
#include "MetavoxelSystem.h"
|
#include "MetavoxelSystem.h"
|
||||||
|
@ -96,6 +97,7 @@ class Application : public QApplication, public PacketSenderNotify {
|
||||||
|
|
||||||
friend class VoxelPacketProcessor;
|
friend class VoxelPacketProcessor;
|
||||||
friend class VoxelEditPacketSender;
|
friend class VoxelEditPacketSender;
|
||||||
|
friend class DatagramProcessor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Application* getInstance() { return static_cast<Application*>(QCoreApplication::instance()); }
|
static Application* getInstance() { return static_cast<Application*>(QCoreApplication::instance()); }
|
||||||
|
@ -208,8 +210,6 @@ public slots:
|
||||||
void domainChanged(const QString& domainHostname);
|
void domainChanged(const QString& domainHostname);
|
||||||
void nodeKilled(SharedNodePointer node);
|
void nodeKilled(SharedNodePointer node);
|
||||||
|
|
||||||
void processDatagrams();
|
|
||||||
|
|
||||||
void exportVoxels();
|
void exportVoxels();
|
||||||
void importVoxels();
|
void importVoxels();
|
||||||
void cutVoxels();
|
void cutVoxels();
|
||||||
|
@ -230,7 +230,6 @@ private slots:
|
||||||
|
|
||||||
void timer();
|
void timer();
|
||||||
void idle();
|
void idle();
|
||||||
void terminate();
|
|
||||||
|
|
||||||
void setFullscreen(bool fullscreen);
|
void setFullscreen(bool fullscreen);
|
||||||
void setEnable3DTVMode(bool enable3DTVMode);
|
void setEnable3DTVMode(bool enable3DTVMode);
|
||||||
|
@ -332,6 +331,9 @@ private:
|
||||||
|
|
||||||
BandwidthMeter _bandwidthMeter;
|
BandwidthMeter _bandwidthMeter;
|
||||||
|
|
||||||
|
QThread* _nodeThread;
|
||||||
|
DatagramProcessor _datagramProcessor;
|
||||||
|
|
||||||
QNetworkAccessManager* _networkAccessManager;
|
QNetworkAccessManager* _networkAccessManager;
|
||||||
QSettings* _settings;
|
QSettings* _settings;
|
||||||
|
|
||||||
|
@ -461,11 +463,8 @@ private:
|
||||||
VoxelEditPacketSender _voxelEditSender;
|
VoxelEditPacketSender _voxelEditSender;
|
||||||
ParticleEditPacketSender _particleEditSender;
|
ParticleEditPacketSender _particleEditSender;
|
||||||
|
|
||||||
unsigned char _incomingPacket[MAX_PACKET_SIZE];
|
|
||||||
int _packetCount;
|
|
||||||
int _packetsPerSecond;
|
int _packetsPerSecond;
|
||||||
int _bytesPerSecond;
|
int _bytesPerSecond;
|
||||||
int _bytesCount;
|
|
||||||
|
|
||||||
int _recentMaxPackets; // recent max incoming voxel packets to process
|
int _recentMaxPackets; // recent max incoming voxel packets to process
|
||||||
bool _resetRecentMaxPacketsSoon;
|
bool _resetRecentMaxPacketsSoon;
|
||||||
|
|
|
@ -443,6 +443,15 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
|
||||||
QByteArray outputBuffer;
|
QByteArray outputBuffer;
|
||||||
outputBuffer.resize(numRequiredOutputSamples * sizeof(int16_t));
|
outputBuffer.resize(numRequiredOutputSamples * sizeof(int16_t));
|
||||||
|
|
||||||
|
|
||||||
|
if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) {
|
||||||
|
// we don't have any audio data left in the output buffer
|
||||||
|
// we just starved
|
||||||
|
qDebug() << "Audio output just starved.";
|
||||||
|
_ringBuffer.setIsStarved(true);
|
||||||
|
_numFramesDisplayStarve = 10;
|
||||||
|
}
|
||||||
|
|
||||||
// if there is anything in the ring buffer, decide what to do
|
// if there is anything in the ring buffer, decide what to do
|
||||||
if (_ringBuffer.samplesAvailable() > 0) {
|
if (_ringBuffer.samplesAvailable() > 0) {
|
||||||
if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO
|
if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO
|
||||||
|
@ -515,12 +524,6 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (_audioOutput->bytesFree() == _audioOutput->bufferSize()) {
|
|
||||||
// we don't have any audio data left in the output buffer, and the ring buffer from
|
|
||||||
// the network has nothing in it either - we just starved
|
|
||||||
qDebug() << "Audio output just starved.";
|
|
||||||
_ringBuffer.setIsStarved(true);
|
|
||||||
_numFramesDisplayStarve = 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size());
|
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size());
|
||||||
|
|
110
interface/src/DatagramProcessor.cpp
Normal file
110
interface/src/DatagramProcessor.cpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
//
|
||||||
|
// DatagramProcessor.cpp
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 1/23/2014.
|
||||||
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <PerfStat.h>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "Menu.h"
|
||||||
|
|
||||||
|
#include "DatagramProcessor.h"
|
||||||
|
|
||||||
|
DatagramProcessor::DatagramProcessor(QObject* parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatagramProcessor::processDatagrams() {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"DatagramProcessor::processDatagrams()");
|
||||||
|
|
||||||
|
HifiSockAddr senderSockAddr;
|
||||||
|
ssize_t bytesReceived;
|
||||||
|
|
||||||
|
static unsigned char incomingPacket[MAX_PACKET_SIZE];
|
||||||
|
|
||||||
|
Application* application = Application::getInstance();
|
||||||
|
|
||||||
|
while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams() &&
|
||||||
|
(bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) incomingPacket,
|
||||||
|
MAX_PACKET_SIZE,
|
||||||
|
senderSockAddr.getAddressPointer(),
|
||||||
|
senderSockAddr.getPortPointer()))) {
|
||||||
|
|
||||||
|
_packetCount++;
|
||||||
|
_byteCount += bytesReceived;
|
||||||
|
|
||||||
|
if (packetVersionMatch(incomingPacket)) {
|
||||||
|
// only process this packet if we have a match on the packet version
|
||||||
|
switch (incomingPacket[0]) {
|
||||||
|
case PACKET_TYPE_TRANSMITTER_DATA_V2:
|
||||||
|
// V2 = IOS transmitter app
|
||||||
|
application->_myTransmitter.processIncomingData(incomingPacket, bytesReceived);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_MIXED_AUDIO:
|
||||||
|
QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection,
|
||||||
|
Q_ARG(QByteArray, QByteArray((char*) incomingPacket, bytesReceived)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PACKET_TYPE_PARTICLE_ADD_RESPONSE:
|
||||||
|
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||||
|
Particle::handleAddParticleResponse(incomingPacket, bytesReceived);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PACKET_TYPE_PARTICLE_DATA:
|
||||||
|
case PACKET_TYPE_PARTICLE_ERASE:
|
||||||
|
case PACKET_TYPE_VOXEL_DATA:
|
||||||
|
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()");
|
||||||
|
|
||||||
|
bool wantExtraDebugging = application->getLogger()->extraDebugging();
|
||||||
|
if (wantExtraDebugging && incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) {
|
||||||
|
int numBytesPacketHeader = numBytesForPacketHeader(incomingPacket);
|
||||||
|
unsigned char* dataAt = incomingPacket + numBytesPacketHeader;
|
||||||
|
dataAt += sizeof(VOXEL_PACKET_FLAGS);
|
||||||
|
VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt);
|
||||||
|
dataAt += sizeof(VOXEL_PACKET_SEQUENCE);
|
||||||
|
VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt);
|
||||||
|
dataAt += sizeof(VOXEL_PACKET_SENT_TIME);
|
||||||
|
VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
|
||||||
|
int flightTime = arrivedAt - sentAt;
|
||||||
|
|
||||||
|
printf("got PACKET_TYPE_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add this packet to our list of voxel packets and process them on the voxel processing
|
||||||
|
application->_voxelProcessor.queueReceivedPacket(senderSockAddr, incomingPacket, bytesReceived);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKET_TYPE_METAVOXEL_DATA:
|
||||||
|
application->_metavoxels.processData(QByteArray((const char*) incomingPacket, bytesReceived),
|
||||||
|
senderSockAddr);
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_BULK_AVATAR_DATA:
|
||||||
|
NodeList::getInstance()->processBulkNodeData(senderSockAddr,
|
||||||
|
incomingPacket,
|
||||||
|
bytesReceived);
|
||||||
|
application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived);
|
||||||
|
break;
|
||||||
|
case PACKET_TYPE_DATA_SERVER_GET:
|
||||||
|
case PACKET_TYPE_DATA_SERVER_PUT:
|
||||||
|
case PACKET_TYPE_DATA_SERVER_SEND:
|
||||||
|
case PACKET_TYPE_DATA_SERVER_CONFIRM:
|
||||||
|
DataServerClient::processMessageFromDataServer(incomingPacket, bytesReceived);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NodeList::getInstance()->processNodeData(senderSockAddr, incomingPacket, bytesReceived);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
interface/src/DatagramProcessor.h
Normal file
31
interface/src/DatagramProcessor.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// DatagramProcessor.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 1/23/2014.
|
||||||
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __hifi__DatagramProcessor__
|
||||||
|
#define __hifi__DatagramProcessor__
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
class DatagramProcessor : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DatagramProcessor(QObject* parent = 0);
|
||||||
|
|
||||||
|
int getPacketCount() const { return _packetCount; }
|
||||||
|
int getByteCount() const { return _byteCount; }
|
||||||
|
|
||||||
|
void resetCounters() { _packetCount = 0; _byteCount = 0; }
|
||||||
|
public slots:
|
||||||
|
void processDatagrams();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _packetCount;
|
||||||
|
int _byteCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__hifi__DatagramProcessor__) */
|
|
@ -356,6 +356,7 @@ Menu::Menu() :
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false);
|
||||||
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false);
|
||||||
|
|
||||||
addDisabledActionAndSeparator(developerMenu, "Testing");
|
addDisabledActionAndSeparator(developerMenu, "Testing");
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,7 @@ namespace MenuOption {
|
||||||
const QString ExportVoxels = "Export Voxels";
|
const QString ExportVoxels = "Export Voxels";
|
||||||
const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes";
|
const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes";
|
||||||
const QString HeadMouse = "Head Mouse";
|
const QString HeadMouse = "Head Mouse";
|
||||||
|
const QString HandsCollideWithSelf = "Collide With Self";
|
||||||
const QString FaceshiftTCP = "Faceshift (TCP)";
|
const QString FaceshiftTCP = "Faceshift (TCP)";
|
||||||
const QString FalseColorByDistance = "FALSE Color By Distance";
|
const QString FalseColorByDistance = "FALSE Color By Distance";
|
||||||
const QString FalseColorBySource = "FALSE Color By Source";
|
const QString FalseColorBySource = "FALSE Color By Source";
|
||||||
|
|
|
@ -331,27 +331,29 @@ void renderWorldBox() {
|
||||||
glVertex3f(TREE_SCALE, 0, TREE_SCALE);
|
glVertex3f(TREE_SCALE, 0, TREE_SCALE);
|
||||||
glVertex3f(TREE_SCALE, 0, 0);
|
glVertex3f(TREE_SCALE, 0, 0);
|
||||||
glEnd();
|
glEnd();
|
||||||
// Draw marker dots at very end
|
// Draw meter markers along the 3 axis to help with measuring things
|
||||||
|
const float MARKER_DISTANCE = 1.f;
|
||||||
|
const float MARKER_RADIUS = 0.05f;
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(TREE_SCALE, 0, 0);
|
glTranslatef(MARKER_DISTANCE, 0, 0);
|
||||||
glColor3fv(red);
|
glColor3fv(red);
|
||||||
glutSolidSphere(0.125, 10, 10);
|
glutSolidSphere(MARKER_RADIUS, 10, 10);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(0, TREE_SCALE, 0);
|
glTranslatef(0, MARKER_DISTANCE, 0);
|
||||||
glColor3fv(green);
|
glColor3fv(green);
|
||||||
glutSolidSphere(0.125, 10, 10);
|
glutSolidSphere(MARKER_RADIUS, 10, 10);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(0, 0, TREE_SCALE);
|
glTranslatef(0, 0, MARKER_DISTANCE);
|
||||||
glColor3fv(blue);
|
glColor3fv(blue);
|
||||||
glutSolidSphere(0.125, 10, 10);
|
glutSolidSphere(MARKER_RADIUS, 10, 10);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glColor3fv(gray);
|
glColor3fv(gray);
|
||||||
glTranslatef(TREE_SCALE, 0, TREE_SCALE);
|
glTranslatef(MARKER_DISTANCE, 0, MARKER_DISTANCE);
|
||||||
glutSolidSphere(0.125, 10, 10);
|
glutSolidSphere(MARKER_RADIUS, 10, 10);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,7 @@ void Hand::updateCollisions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::HandsCollideWithSelf)) {
|
||||||
// and the current avatar (ignoring everything below the parent of the parent of the last free joint)
|
// and the current avatar (ignoring everything below the parent of the parent of the last free joint)
|
||||||
glm::vec3 owningPenetration;
|
glm::vec3 owningPenetration;
|
||||||
const Model& skeletonModel = _owningAvatar->getSkeletonModel();
|
const Model& skeletonModel = _owningAvatar->getSkeletonModel();
|
||||||
|
@ -240,6 +241,7 @@ void Hand::updateCollisions() {
|
||||||
if (_owningAvatar->findSpherePenetration(palm.getPosition(), scaledPalmRadius, owningPenetration, skipIndex)) {
|
if (_owningAvatar->findSpherePenetration(palm.getPosition(), scaledPalmRadius, owningPenetration, skipIndex)) {
|
||||||
totalPenetration = addPenetrations(totalPenetration, owningPenetration);
|
totalPenetration = addPenetrations(totalPenetration, owningPenetration);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// un-penetrate
|
// un-penetrate
|
||||||
palm.addToPosition(-totalPenetration);
|
palm.addToPosition(-totalPenetration);
|
||||||
|
|
|
@ -569,8 +569,7 @@ void OctreeServer::run() {
|
||||||
nodeList->setOwnerType(getMyNodeType());
|
nodeList->setOwnerType(getMyNodeType());
|
||||||
|
|
||||||
// we need to ask the DS about agents so we can ping/reply with them
|
// 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};
|
nodeList->addNodeTypeToInterestSet(NODE_TYPE_AGENT);
|
||||||
nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
|
|
||||||
|
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ JurisdictionListener::JurisdictionListener(NODE_TYPE type, PacketSenderNotify* n
|
||||||
|
|
||||||
connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &JurisdictionListener::nodeKilled);
|
connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &JurisdictionListener::nodeKilled);
|
||||||
//qDebug("JurisdictionListener::JurisdictionListener(NODE_TYPE type=%c)", type);
|
//qDebug("JurisdictionListener::JurisdictionListener(NODE_TYPE type=%c)", type);
|
||||||
|
|
||||||
|
// tell our NodeList we want to hear about nodes with our node type
|
||||||
|
NodeList::getInstance()->addNodeTypeToInterestSet(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JurisdictionListener::nodeKilled(SharedNodePointer node) {
|
void JurisdictionListener::nodeKilled(SharedNodePointer node) {
|
||||||
|
|
|
@ -1390,9 +1390,8 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) {
|
||||||
bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params);
|
bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params);
|
||||||
unlock();
|
unlock();
|
||||||
|
|
||||||
// if bytesWritten == 0, then it means that the subTree couldn't fit, and so we should reset the packet
|
// if the subTree couldn't fit, and so we should reset the packet and reinsert the node in our bag and try again...
|
||||||
// and reinsert the node in our bag and try again...
|
if (bytesWritten == 0 && (params.stopReason == EncodeBitstreamParams::DIDNT_FIT)) {
|
||||||
if (bytesWritten == 0) {
|
|
||||||
if (packetData.hasContent()) {
|
if (packetData.hasContent()) {
|
||||||
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
|
file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize());
|
||||||
lastPacketWritten = true;
|
lastPacketWritten = true;
|
||||||
|
|
|
@ -682,7 +682,7 @@ void Particle::update(const uint64_t& now) {
|
||||||
const uint64_t REALLY_OLD = 30 * USECS_PER_SECOND; // 30 seconds
|
const uint64_t REALLY_OLD = 30 * USECS_PER_SECOND; // 30 seconds
|
||||||
bool isReallyOld = ((now - _created) > REALLY_OLD);
|
bool isReallyOld = ((now - _created) > REALLY_OLD);
|
||||||
bool isInHand = getInHand();
|
bool isInHand = getInHand();
|
||||||
bool shouldDie = getShouldDie() || (!isInHand && isStopped && isReallyOld);
|
bool shouldDie = (getAge() > getLifetime()) || getShouldDie() || (!isInHand && isStopped && isReallyOld);
|
||||||
setShouldDie(shouldDie);
|
setShouldDie(shouldDie);
|
||||||
|
|
||||||
runUpdateScript(); // allow the javascript to alter our state
|
runUpdateScript(); // allow the javascript to alter our state
|
||||||
|
|
|
@ -42,7 +42,7 @@ const uint16_t PACKET_CONTAINS_INHAND = 128;
|
||||||
const uint16_t PACKET_CONTAINS_SCRIPT = 256;
|
const uint16_t PACKET_CONTAINS_SCRIPT = 256;
|
||||||
const uint16_t PACKET_CONTAINS_SHOULDDIE = 512;
|
const uint16_t PACKET_CONTAINS_SHOULDDIE = 512;
|
||||||
|
|
||||||
const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default
|
const float DEFAULT_LIFETIME = 10.0f; // particles live for 10 seconds by default
|
||||||
const float DEFAULT_DAMPING = 0.99f;
|
const float DEFAULT_DAMPING = 0.99f;
|
||||||
const float DEFAULT_RADIUS = 0.1f / TREE_SCALE;
|
const float DEFAULT_RADIUS = 0.1f / TREE_SCALE;
|
||||||
const float MINIMUM_PARTICLE_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container
|
const float MINIMUM_PARTICLE_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container
|
||||||
|
|
|
@ -278,7 +278,7 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, float elast
|
||||||
void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) {
|
void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) {
|
||||||
|
|
||||||
// consider whether to have the collision make a sound
|
// consider whether to have the collision make a sound
|
||||||
const float AUDIBLE_COLLISION_THRESHOLD = 0.1f;
|
const float AUDIBLE_COLLISION_THRESHOLD = 0.3f;
|
||||||
const float COLLISION_LOUDNESS = 1.f;
|
const float COLLISION_LOUDNESS = 1.f;
|
||||||
const float DURATION_SCALING = 0.004f;
|
const float DURATION_SCALING = 0.004f;
|
||||||
const float NOISE_SCALING = 0.1f;
|
const float NOISE_SCALING = 0.1f;
|
||||||
|
|
|
@ -390,17 +390,29 @@ bool ParticleTree::encodeParticlesDeletedSince(uint64_t& sinceTime, unsigned cha
|
||||||
|
|
||||||
// called by the server when it knows all nodes have been sent deleted packets
|
// called by the server when it knows all nodes have been sent deleted packets
|
||||||
void ParticleTree::forgetParticlesDeletedBefore(uint64_t sinceTime) {
|
void ParticleTree::forgetParticlesDeletedBefore(uint64_t sinceTime) {
|
||||||
|
//qDebug() << "forgetParticlesDeletedBefore()";
|
||||||
|
QSet<uint64_t> keysToRemove;
|
||||||
|
|
||||||
_recentlyDeletedParticlesLock.lockForWrite();
|
_recentlyDeletedParticlesLock.lockForWrite();
|
||||||
QMultiMap<uint64_t, uint32_t>::const_iterator iterator = _recentlyDeletedParticleIDs.constBegin();
|
QMultiMap<uint64_t, uint32_t>::iterator iterator = _recentlyDeletedParticleIDs.begin();
|
||||||
while (iterator != _recentlyDeletedParticleIDs.constEnd()) {
|
// First find all the keys in the map that are older and need to be deleted
|
||||||
|
while (iterator != _recentlyDeletedParticleIDs.end()) {
|
||||||
//qDebug() << "considering... time/key:" << iterator.key();
|
//qDebug() << "considering... time/key:" << iterator.key();
|
||||||
if (iterator.key() <= sinceTime) {
|
if (iterator.key() <= sinceTime) {
|
||||||
//qDebug() << "YES older... time/key:" << iterator.key();
|
//qDebug() << "YES older... time/key:" << iterator.key();
|
||||||
_recentlyDeletedParticleIDs.remove(iterator.key());
|
keysToRemove << iterator.key();
|
||||||
}
|
}
|
||||||
++iterator;
|
++iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now run through the keysToRemove and remove them
|
||||||
|
foreach (uint64_t value, keysToRemove) {
|
||||||
|
//qDebug() << "removing the key, _recentlyDeletedParticleIDs.remove(value); time/key:" << value;
|
||||||
|
_recentlyDeletedParticleIDs.remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
_recentlyDeletedParticlesLock.unlock();
|
_recentlyDeletedParticlesLock.unlock();
|
||||||
|
//qDebug() << "DONE forgetParticlesDeletedBefore()";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,8 +74,6 @@ const char* Node::getTypeName() const {
|
||||||
return NODE_TYPE_NAME_AUDIO_MIXER;
|
return NODE_TYPE_NAME_AUDIO_MIXER;
|
||||||
case NODE_TYPE_AVATAR_MIXER:
|
case NODE_TYPE_AVATAR_MIXER:
|
||||||
return NODE_TYPE_NAME_AVATAR_MIXER;
|
return NODE_TYPE_NAME_AVATAR_MIXER;
|
||||||
case NODE_TYPE_AUDIO_INJECTOR:
|
|
||||||
return NODE_TYPE_NAME_AUDIO_INJECTOR;
|
|
||||||
case NODE_TYPE_ANIMATION_SERVER:
|
case NODE_TYPE_ANIMATION_SERVER:
|
||||||
return NODE_TYPE_NAME_ANIMATION_SERVER;
|
return NODE_TYPE_NAME_ANIMATION_SERVER;
|
||||||
case NODE_TYPE_UNASSIGNED:
|
case NODE_TYPE_UNASSIGNED:
|
||||||
|
|
|
@ -59,9 +59,9 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
|
||||||
_nodeHashMutex(),
|
_nodeHashMutex(),
|
||||||
_domainHostname(DEFAULT_DOMAIN_HOSTNAME),
|
_domainHostname(DEFAULT_DOMAIN_HOSTNAME),
|
||||||
_domainSockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
|
_domainSockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
|
||||||
_nodeSocket(),
|
_nodeSocket(this),
|
||||||
_ownerType(newOwnerType),
|
_ownerType(newOwnerType),
|
||||||
_nodeTypesOfInterest(NULL),
|
_nodeTypesOfInterest(),
|
||||||
_ownerUUID(QUuid::createUuid()),
|
_ownerUUID(QUuid::createUuid()),
|
||||||
_numNoReplyDomainCheckIns(0),
|
_numNoReplyDomainCheckIns(0),
|
||||||
_assignmentServerSocket(),
|
_assignmentServerSocket(),
|
||||||
|
@ -75,8 +75,6 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
|
||||||
|
|
||||||
|
|
||||||
NodeList::~NodeList() {
|
NodeList::~NodeList() {
|
||||||
delete _nodeTypesOfInterest;
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +234,11 @@ int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr,
|
||||||
node->setLastHeardMicrostamp(usecTimestampNow());
|
node->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
|
|
||||||
if (!senderSockAddr.isNull()) {
|
if (!senderSockAddr.isNull()) {
|
||||||
activateSocketFromNodeCommunication(senderSockAddr);
|
if (senderSockAddr == node->getPublicSocket()) {
|
||||||
|
node->activatePublicSocket();
|
||||||
|
} else if (senderSockAddr == node->getLocalSocket()) {
|
||||||
|
node->activateLocalSocket();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->getActiveSocket() || senderSockAddr.isNull()) {
|
if (node->getActiveSocket() || senderSockAddr.isNull()) {
|
||||||
|
@ -257,7 +259,7 @@ int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr,
|
||||||
SharedNodePointer NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) {
|
SharedNodePointer NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) {
|
||||||
// naively returns the first node that has a matching active HifiSockAddr
|
// naively returns the first node that has a matching active HifiSockAddr
|
||||||
// note that there can be multiple nodes that have a matching active socket, so this isn't a good way to uniquely identify
|
// note that there can be multiple nodes that have a matching active socket, so this isn't a good way to uniquely identify
|
||||||
foreach (const SharedNodePointer& node, _nodeHash) {
|
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||||
if (node->getActiveSocket() && *node->getActiveSocket() == senderSockAddr) {
|
if (node->getActiveSocket() && *node->getActiveSocket() == senderSockAddr) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -293,19 +295,18 @@ void NodeList::reset() {
|
||||||
clear();
|
clear();
|
||||||
_numNoReplyDomainCheckIns = 0;
|
_numNoReplyDomainCheckIns = 0;
|
||||||
|
|
||||||
delete _nodeTypesOfInterest;
|
_nodeTypesOfInterest.clear();
|
||||||
_nodeTypesOfInterest = NULL;
|
|
||||||
|
|
||||||
// refresh the owner UUID
|
// refresh the owner UUID
|
||||||
_ownerUUID = QUuid::createUuid();
|
_ownerUUID = QUuid::createUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) {
|
void NodeList::addNodeTypeToInterestSet(NODE_TYPE nodeTypeToAdd) {
|
||||||
delete _nodeTypesOfInterest;
|
_nodeTypesOfInterest << nodeTypeToAdd;
|
||||||
|
}
|
||||||
|
|
||||||
_nodeTypesOfInterest = new char[numNodeTypesOfInterest + sizeof(char)];
|
void NodeList::addSetOfNodeTypesToNodeInterestSet(const QSet<NODE_TYPE>& setOfNodeTypes) {
|
||||||
memcpy(_nodeTypesOfInterest, nodeTypesOfInterest, numNodeTypesOfInterest);
|
_nodeTypesOfInterest.unite(setOfNodeTypes);
|
||||||
_nodeTypesOfInterest[numNodeTypesOfInterest] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442;
|
const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442;
|
||||||
|
@ -522,7 +523,7 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
sendSTUNRequest();
|
sendSTUNRequest();
|
||||||
} else {
|
} else {
|
||||||
// construct the DS check in packet if we need to
|
// construct the DS check in packet if we need to
|
||||||
int numBytesNodesOfInterest = _nodeTypesOfInterest ? strlen((char*) _nodeTypesOfInterest) : 0;
|
int numBytesNodesOfInterest = _nodeTypesOfInterest.size();
|
||||||
|
|
||||||
const int IP_ADDRESS_BYTES = 4;
|
const int IP_ADDRESS_BYTES = 4;
|
||||||
|
|
||||||
|
@ -563,11 +564,8 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
*(packetPosition++) = numBytesNodesOfInterest;
|
*(packetPosition++) = numBytesNodesOfInterest;
|
||||||
|
|
||||||
// copy over the bytes for node types of interest, if required
|
// copy over the bytes for node types of interest, if required
|
||||||
if (numBytesNodesOfInterest > 0) {
|
foreach (NODE_TYPE nodeTypeOfInterest, _nodeTypesOfInterest) {
|
||||||
memcpy(packetPosition,
|
*(packetPosition++) = nodeTypeOfInterest;
|
||||||
_nodeTypesOfInterest,
|
|
||||||
numBytesNodesOfInterest);
|
|
||||||
packetPosition += numBytesNodesOfInterest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_nodeSocket.writeDatagram((char*) checkInPacket, packetPosition - checkInPacket,
|
_nodeSocket.writeDatagram((char*) checkInPacket, packetPosition - checkInPacket,
|
||||||
|
@ -738,7 +736,7 @@ SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||||
unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
|
unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
|
|
||||||
foreach (const SharedNodePointer& node, _nodeHash) {
|
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||||
// only send to the NodeTypes we are asked to send to.
|
// only send to the NodeTypes we are asked to send to.
|
||||||
if (memchr(nodeTypes, node->getType(), numNodeTypes)) {
|
if (memchr(nodeTypes, node->getType(), numNodeTypes)) {
|
||||||
if (getNodeActiveSocketOrPing(node.data())) {
|
if (getNodeActiveSocketOrPing(node.data())) {
|
||||||
|
@ -754,7 +752,7 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::pingInactiveNodes() {
|
void NodeList::pingInactiveNodes() {
|
||||||
foreach (const SharedNodePointer& node, _nodeHash) {
|
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||||
if (!node->getActiveSocket()) {
|
if (!node->getActiveSocket()) {
|
||||||
// we don't have an active link to this node, ping it to set that up
|
// we don't have an active link to this node, ping it to set that up
|
||||||
pingPublicAndLocalSocketsForInactiveNode(node.data());
|
pingPublicAndLocalSocketsForInactiveNode(node.data());
|
||||||
|
@ -791,7 +789,7 @@ void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddre
|
||||||
SharedNodePointer NodeList::soloNodeOfType(char nodeType) {
|
SharedNodePointer NodeList::soloNodeOfType(char nodeType) {
|
||||||
|
|
||||||
if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) {
|
if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) {
|
||||||
foreach (const SharedNodePointer& node, _nodeHash) {
|
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||||
if (node->getType() == nodeType) {
|
if (node->getType() == nodeType) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QtCore/QMutex>
|
#include <QtCore/QMutex>
|
||||||
|
#include <QtCore/QSet>
|
||||||
#include <QtCore/QSettings>
|
#include <QtCore/QSettings>
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtNetwork/QHostAddress>
|
#include <QtNetwork/QHostAddress>
|
||||||
|
@ -87,10 +88,10 @@ public:
|
||||||
|
|
||||||
int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; }
|
int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; }
|
||||||
|
|
||||||
void clear();
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
|
void addNodeTypeToInterestSet(NODE_TYPE nodeTypeToAdd);
|
||||||
|
void addSetOfNodeTypesToNodeInterestSet(const QSet<NODE_TYPE>& setOfNodeTypes);
|
||||||
|
|
||||||
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ private:
|
||||||
HifiSockAddr _domainSockAddr;
|
HifiSockAddr _domainSockAddr;
|
||||||
QUdpSocket _nodeSocket;
|
QUdpSocket _nodeSocket;
|
||||||
char _ownerType;
|
char _ownerType;
|
||||||
char* _nodeTypesOfInterest;
|
QSet<NODE_TYPE> _nodeTypesOfInterest;
|
||||||
QUuid _ownerUUID;
|
QUuid _ownerUUID;
|
||||||
int _numNoReplyDomainCheckIns;
|
int _numNoReplyDomainCheckIns;
|
||||||
HifiSockAddr _assignmentServerSocket;
|
HifiSockAddr _assignmentServerSocket;
|
||||||
|
@ -163,6 +164,7 @@ private:
|
||||||
void timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData);
|
void timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData);
|
||||||
void resetDomainData(char domainField[], const char* domainData);
|
void resetDomainData(char domainField[], const char* domainData);
|
||||||
void domainLookup();
|
void domainLookup();
|
||||||
|
void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__NodeList__) */
|
#endif /* defined(__hifi__NodeList__) */
|
||||||
|
|
|
@ -25,7 +25,6 @@ const NODE_TYPE NODE_TYPE_ENVIRONMENT_SERVER = 'E';
|
||||||
const NODE_TYPE NODE_TYPE_AGENT = 'I';
|
const NODE_TYPE NODE_TYPE_AGENT = 'I';
|
||||||
const NODE_TYPE NODE_TYPE_AUDIO_MIXER = 'M';
|
const NODE_TYPE NODE_TYPE_AUDIO_MIXER = 'M';
|
||||||
const NODE_TYPE NODE_TYPE_AVATAR_MIXER = 'W';
|
const NODE_TYPE NODE_TYPE_AVATAR_MIXER = 'W';
|
||||||
const NODE_TYPE NODE_TYPE_AUDIO_INJECTOR = 'A';
|
|
||||||
const NODE_TYPE NODE_TYPE_ANIMATION_SERVER = 'a';
|
const NODE_TYPE NODE_TYPE_ANIMATION_SERVER = 'a';
|
||||||
const NODE_TYPE NODE_TYPE_UNASSIGNED = 1;
|
const NODE_TYPE NODE_TYPE_UNASSIGNED = 1;
|
||||||
|
|
||||||
|
|
|
@ -68,4 +68,6 @@ void VoxelServer::beforeRun() {
|
||||||
qDebug("Using Minimal Environment=%s", debug::valueOf(_sendMinimalEnvironment));
|
qDebug("Using Minimal Environment=%s", debug::valueOf(_sendMinimalEnvironment));
|
||||||
}
|
}
|
||||||
qDebug("Sending environments=%s", debug::valueOf(_sendEnvironments));
|
qDebug("Sending environments=%s", debug::valueOf(_sendEnvironments));
|
||||||
|
|
||||||
|
NodeList::getInstance()->addNodeTypeToInterestSet(NODE_TYPE_ANIMATION_SERVER);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue