From 1c4163b010cc95791863e8f07bf4154e2ca7b011 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 11:12:14 -0800 Subject: [PATCH 01/46] add guards against buffer overflow in voxel server for edit/delete voxel packets --- .../src/VoxelServerPacketProcessor.cpp | 32 +++++++++++-------- libraries/voxels/src/VoxelTree.cpp | 14 +++++--- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index 9b79ae121a..a60f8e89ee 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -49,25 +49,31 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned int atByte = numBytesPacketHeader + sizeof(itemNumber); unsigned char* voxelData = (unsigned char*)&packetData[atByte]; while (atByte < packetLength) { - unsigned char octets = (unsigned char)*voxelData; + unsigned char octets = numberOfThreeBitSectionsInCode(voxelData); const int COLOR_SIZE_IN_BYTES = 3; int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES; int voxelCodeSize = bytesRequiredForCodeLength(octets); - if (_myServer->wantShowAnimationDebug()) { - int red = voxelData[voxelCodeSize + 0]; - int green = voxelData[voxelCodeSize + 1]; - int blue = voxelData[voxelCodeSize + 2]; + if (atByte + voxelDataSize <= packetLength) { + if (_myServer->wantShowAnimationDebug()) { + int red = voxelData[voxelCodeSize + 0]; + int green = voxelData[voxelCodeSize + 1]; + int blue = voxelData[voxelCodeSize + 2]; - 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; - } + 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; + } - _myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive); - // skip to next - voxelData += voxelDataSize; - atByte += voxelDataSize; + _myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive); + + // 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; + } } // Make sure our Node and NodeList knows we've heard from this node. diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 251a6300f2..ec86912a51 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -583,11 +583,15 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe while (atByte < bufferSizeBytes) { int codeLength = numberOfThreeBitSectionsInCode(voxelCode); int voxelDataSize = bytesRequiredForCodeLength(codeLength) + SIZE_OF_COLOR_DATA; - - deleteVoxelCodeFromTree(voxelCode, COLLAPSE_EMPTY_TREE); - - voxelCode+=voxelDataSize; - atByte+=voxelDataSize; + + if (atByte + voxelDataSize <= bufferSizeBytes) { + deleteVoxelCodeFromTree(voxelCode, COLLAPSE_EMPTY_TREE); + voxelCode+=voxelDataSize; + atByte+=voxelDataSize; + } else { + printf("WARNING! Got remove voxel bitstream that would overflow buffer, bailing processing!\n"); + break; + } } } From adf0feed296b2ebb7e007e2907dd720203a01f52 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 11:14:29 -0800 Subject: [PATCH 02/46] style clenaup --- .../voxel-server-library/src/VoxelServerPacketProcessor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index a60f8e89ee..53a6267a7a 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -56,9 +56,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned if (atByte + voxelDataSize <= packetLength) { if (_myServer->wantShowAnimationDebug()) { - int red = voxelData[voxelCodeSize + 0]; - int green = voxelData[voxelCodeSize + 1]; - int blue = voxelData[voxelCodeSize + 2]; + 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); From 145efbda2df49d4678f90a6c78fb78921a411667 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Nov 2013 11:21:32 -0800 Subject: [PATCH 03/46] some dialog touchups and visual changes --- interface/src/Menu.cpp | 178 +++++++++++++---------------------------- 1 file changed, 57 insertions(+), 121 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a1f83007fd..d4641af851 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -8,15 +8,17 @@ #include -#include + #include #include #include #include #include #include +#include #include #include +#include #include #include #include @@ -728,60 +730,29 @@ void updateDSHostname(const QString& domainServerHostname) { } const int QLINE_MINIMUM_WIDTH = 400; - - -QLineEdit* lineEditForDomainHostname() { - QString currentDomainHostname = NodeList::getInstance()->getDomainHostname(); - - if (NodeList::getInstance()->getDomainPort() != DEFAULT_DOMAIN_SERVER_PORT) { - // add the port to the currentDomainHostname string if it is custom - currentDomainHostname.append(QString(":%1").arg(NodeList::getInstance()->getDomainPort())); - } - - QLineEdit* domainServerLineEdit = new QLineEdit(currentDomainHostname); - domainServerLineEdit->setPlaceholderText(DEFAULT_DOMAIN_HOSTNAME); - domainServerLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); - - return domainServerLineEdit; -} - +const float DIALOG_RATIO_OF_WINDOW = 0.30; void Menu::login() { - Application* applicationInstance = Application::getInstance(); - QDialog dialog; - dialog.setWindowTitle("Login"); - QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); - dialog.setLayout(layout); + QInputDialog loginDialog(Application::getInstance()->getWindow()); + loginDialog.setWindowTitle("Login"); + loginDialog.setLabelText("Username:"); + QString username = Application::getInstance()->getProfile()->getUsername(); + loginDialog.setTextValue(username); + loginDialog.setWindowFlags(Qt::Sheet); + loginDialog.resize(loginDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, loginDialog.size().height()); - QFormLayout* form = new QFormLayout(); - layout->addLayout(form, 1); - - QString username = applicationInstance->getProfile()->getUsername(); - QLineEdit* usernameLineEdit = new QLineEdit(username); - usernameLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); - form->addRow("Username:", usernameLineEdit); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); - dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); - layout->addWidget(buttons); - - int ret = dialog.exec(); - if (ret != QDialog::Accepted) { - return; - } - - if (usernameLineEdit->text() != username) { + int dialogReturn = loginDialog.exec(); + if (dialogReturn == QDialog::Accepted && loginDialog.textValue().isEmpty() && loginDialog.textValue() != username) { // there has been a username change // ask for a profile reset with the new username - applicationInstance->resetProfile(usernameLineEdit->text()); + Application::getInstance()->resetProfile(loginDialog.textValue()); } } void Menu::editPreferences() { Application* applicationInstance = Application::getInstance(); - QDialog dialog; + QDialog dialog(applicationInstance->getWindow()); dialog.setWindowTitle("Interface Preferences"); QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); dialog.setLayout(layout); @@ -888,70 +859,48 @@ void Menu::editPreferences() { } void Menu::goToDomain() { - QDialog dialog; - dialog.setWindowTitle("Go To Domain"); - QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); - dialog.setLayout(layout); - QFormLayout* form = new QFormLayout(); - layout->addLayout(form, 1); - + QString currentDomainHostname = NodeList::getInstance()->getDomainHostname(); - QLineEdit* domainServerLineEdit = lineEditForDomainHostname(); - form->addRow("Domain server:", domainServerLineEdit); + if (NodeList::getInstance()->getDomainPort() != DEFAULT_DOMAIN_SERVER_PORT) { + // add the port to the currentDomainHostname string if it is custom + currentDomainHostname.append(QString(":%1").arg(NodeList::getInstance()->getDomainPort())); + } - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); - dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); - layout->addWidget(buttons); + QInputDialog domainDialog(Application::getInstance()->getWindow()); + domainDialog.setWindowTitle("Go to Domain"); + domainDialog.setLabelText("Domain server:"); + domainDialog.setTextValue(currentDomainHostname); + domainDialog.setWindowFlags(Qt::Sheet); + domainDialog.resize(domainDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, domainDialog.size().height()); - int ret = dialog.exec(); - if (ret != QDialog::Accepted) { - return; - } - - updateDSHostname(domainServerLineEdit->text()); + int dialogReturn = domainDialog.exec(); + if (dialogReturn == QDialog::Accepted && domainDialog.textValue().isEmpty()) { + updateDSHostname(domainDialog.textValue()); + } } void Menu::goToLocation() { - QDialog dialog; - dialog.setWindowTitle("Go To Location"); - QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); - dialog.setLayout(layout); - - QFormLayout* form = new QFormLayout(); - layout->addLayout(form, 1); - - const int QLINE_MINIMUM_WIDTH = 300; - - Application* applicationInstance = Application::getInstance(); - MyAvatar* myAvatar = applicationInstance->getAvatar(); + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); glm::vec3 avatarPos = myAvatar->getPosition(); - QString currentLocation = QString("%1, %2, %3").arg(QString::number(avatarPos.x), - QString::number(avatarPos.y), QString::number(avatarPos.z)); - - QLineEdit* coordinates = new QLineEdit(currentLocation); - coordinates->setMinimumWidth(QLINE_MINIMUM_WIDTH); - form->addRow("Coordinates as x,y,z:", coordinates); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); - dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); - layout->addWidget(buttons); - - int ret = dialog.exec(); - if (ret != QDialog::Accepted) { - return; - } - - QByteArray newCoordinates; - - if (coordinates->text().size() > 0) { - // the user input a new hostname, use that + QString currentLocation = QString("%1, %2, %3").arg(QString::number(avatarPos.x), + QString::number(avatarPos.y), QString::number(avatarPos.z)); + + + QInputDialog coordinateDialog(Application::getInstance()->getWindow()); + coordinateDialog.setWindowTitle("Go to Location"); + coordinateDialog.setLabelText("Coordinate as x,y,z:"); + coordinateDialog.setTextValue(currentLocation); + coordinateDialog.setWindowFlags(Qt::Sheet); + coordinateDialog.resize(coordinateDialog.parentWidget()->size().width() * 0.30, coordinateDialog.size().height()); + int dialogReturn = coordinateDialog.exec(); + if (dialogReturn == QDialog::Accepted && !coordinateDialog.textValue().isEmpty()) { + QByteArray newCoordinates; + QString delimiterPattern(","); - QStringList coordinateItems = coordinates->text().split(delimiterPattern); - + QStringList coordinateItems = coordinateDialog.textValue().split(delimiterPattern); + const int NUMBER_OF_COORDINATE_ITEMS = 3; const int X_ITEM = 0; const int Y_ITEM = 1; @@ -971,32 +920,19 @@ void Menu::goToLocation() { } void Menu::goToUser() { - QDialog dialog; - dialog.setWindowTitle("Go To User"); - QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); - dialog.setLayout(layout); + QInputDialog userDialog(Application::getInstance()->getWindow()); + userDialog.setWindowTitle("Go to User"); + userDialog.setLabelText("Destination user:"); + QString username = Application::getInstance()->getProfile()->getUsername(); + userDialog.setTextValue(username); + userDialog.setWindowFlags(Qt::Sheet); + userDialog.resize(userDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, userDialog.size().height()); - QFormLayout* form = new QFormLayout(); - layout->addLayout(form, 1); - - QLineEdit* usernameLineEdit = new QLineEdit(); - usernameLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); - form->addRow("", usernameLineEdit); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); - dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); - layout->addWidget(buttons); - - int ret = dialog.exec(); - if (ret != QDialog::Accepted) { - return; - } - - if (!usernameLineEdit->text().isEmpty()) { + int dialogReturn = userDialog.exec(); + if (dialogReturn == QDialog::Accepted && userDialog.textValue().isEmpty()) { // there's a username entered by the user, make a request to the data-server DataServerClient::getValuesForKeysAndUserString((QStringList() << DataServerKey::Domain << DataServerKey::Position), - usernameLineEdit->text()); + userDialog.textValue()); } } From 4cab991c02e1e67a6b97098a935c1dbbd15c4ded Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 11:24:51 -0800 Subject: [PATCH 04/46] style cleanup --- libraries/voxels/src/VoxelTree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index ec86912a51..e5232718e6 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -586,8 +586,8 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe if (atByte + voxelDataSize <= bufferSizeBytes) { deleteVoxelCodeFromTree(voxelCode, COLLAPSE_EMPTY_TREE); - voxelCode+=voxelDataSize; - atByte+=voxelDataSize; + voxelCode += voxelDataSize; + atByte + =voxelDataSize; } else { printf("WARNING! Got remove voxel bitstream that would overflow buffer, bailing processing!\n"); break; From 60e7c54303f5d85900acbdb99b3ef27f73ffcc1d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Nov 2013 11:26:53 -0800 Subject: [PATCH 05/46] fix some checks for empty inputs --- interface/src/Menu.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d4641af851..0efe582df2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -742,7 +742,7 @@ void Menu::login() { loginDialog.resize(loginDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, loginDialog.size().height()); int dialogReturn = loginDialog.exec(); - if (dialogReturn == QDialog::Accepted && loginDialog.textValue().isEmpty() && loginDialog.textValue() != username) { + if (dialogReturn == QDialog::Accepted && !loginDialog.textValue().isEmpty() && loginDialog.textValue() != username) { // there has been a username change // ask for a profile reset with the new username Application::getInstance()->resetProfile(loginDialog.textValue()); @@ -875,7 +875,7 @@ void Menu::goToDomain() { domainDialog.resize(domainDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, domainDialog.size().height()); int dialogReturn = domainDialog.exec(); - if (dialogReturn == QDialog::Accepted && domainDialog.textValue().isEmpty()) { + if (dialogReturn == QDialog::Accepted && !domainDialog.textValue().isEmpty()) { updateDSHostname(domainDialog.textValue()); } } @@ -929,7 +929,7 @@ void Menu::goToUser() { userDialog.resize(userDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, userDialog.size().height()); int dialogReturn = userDialog.exec(); - if (dialogReturn == QDialog::Accepted && userDialog.textValue().isEmpty()) { + if (dialogReturn == QDialog::Accepted && !userDialog.textValue().isEmpty()) { // there's a username entered by the user, make a request to the data-server DataServerClient::getValuesForKeysAndUserString((QStringList() << DataServerKey::Domain << DataServerKey::Position), userDialog.textValue()); From 9060020279ec119c238744a465733526ceb7ac60 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 11:33:28 -0800 Subject: [PATCH 06/46] style cleanup --- libraries/voxels/src/VoxelTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index e5232718e6..f7f50788c5 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -587,7 +587,7 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe if (atByte + voxelDataSize <= bufferSizeBytes) { deleteVoxelCodeFromTree(voxelCode, COLLAPSE_EMPTY_TREE); voxelCode += voxelDataSize; - atByte + =voxelDataSize; + atByte += voxelDataSize; } else { printf("WARNING! Got remove voxel bitstream that would overflow buffer, bailing processing!\n"); break; From 0c8799bb3db1dbdf77e45c14eec1b05ce32b1114 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Nov 2013 12:12:54 -0800 Subject: [PATCH 07/46] Tweaks to voxel editing: edit from farther away, expand cubes to make sure they show up over voxels, initialize voxel scale with moused-over scale. --- interface/src/Application.cpp | 18 ++++++++++++++---- interface/src/Application.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e1adc6141..908eee237c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -124,6 +124,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _isHoverVoxel(false), _isHoverVoxelSounding(false), _mouseVoxelScale(1.0f / 1024.0f), + _mouseVoxelScaleInitialized(false), _justEditedVoxel(false), _nudgeStarted(false), _lookingAlongX(false), @@ -1782,7 +1783,7 @@ void Application::shrinkMirrorView() { } const float MAX_AVATAR_EDIT_VELOCITY = 1.0f; -const float MAX_VOXEL_EDIT_DISTANCE = 20.0f; +const float MAX_VOXEL_EDIT_DISTANCE = 50.0f; const float HEAD_SPHERE_RADIUS = 0.07; static QUuid DEFAULT_NODE_ID_REF; @@ -2051,6 +2052,8 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, PerformanceWarning warn(showWarnings, "Application::updateMouseVoxels()"); _mouseVoxel.s = 0.0f; + bool wasInitialized = _mouseVoxelScaleInitialized; + _mouseVoxelScaleInitialized = false; if (Menu::getInstance()->isVoxelModeActionChecked() && (fabs(_myAvatar.getVelocity().x) + fabs(_myAvatar.getVelocity().y) + @@ -2058,6 +2061,12 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) { if (distance < MAX_VOXEL_EDIT_DISTANCE) { + // set the voxel scale to that of the first moused-over voxel + if (!wasInitialized) { + _mouseVoxelScale = _mouseVoxel.s; + } + _mouseVoxelScaleInitialized = true; + // find the nearest voxel with the desired scale if (_mouseVoxelScale > _mouseVoxel.s) { // choose the larger voxel that encompasses the one selected @@ -2990,6 +2999,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glDisable(GL_LIGHTING); glPushMatrix(); glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); + const float CUBE_EXPANSION = 1.01f; if (_nudgeStarted) { renderNudgeGuide(_nudgeGuidePosition.x, _nudgeGuidePosition.y, _nudgeGuidePosition.z, _nudgeVoxel.s); renderNudgeGrid(_nudgeVoxel.x, _nudgeVoxel.y, _nudgeVoxel.z, _nudgeVoxel.s, _mouseVoxel.s); @@ -2999,7 +3009,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { _nudgeVoxel.z + _nudgeVoxel.s * 0.5f); glColor3ub(255, 255, 255); glLineWidth(4.0f); - glutWireCube(_nudgeVoxel.s); + glutWireCube(_nudgeVoxel.s * CUBE_EXPANSION); glPopMatrix(); } else { renderMouseVoxelGrid(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); @@ -3018,13 +3028,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { _nudgeGuidePosition.y + _nudgeVoxel.s*0.5f, _nudgeGuidePosition.z + _nudgeVoxel.s*0.5f); glLineWidth(4.0f); - glutWireCube(_nudgeVoxel.s); + glutWireCube(_nudgeVoxel.s * CUBE_EXPANSION); } else { glTranslatef(_mouseVoxel.x + _mouseVoxel.s*0.5f, _mouseVoxel.y + _mouseVoxel.s*0.5f, _mouseVoxel.z + _mouseVoxel.s*0.5f); glLineWidth(4.0f); - glutWireCube(_mouseVoxel.s); + glutWireCube(_mouseVoxel.s * CUBE_EXPANSION); } glLineWidth(1.0f); glPopMatrix(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 9f46720d84..4e370c9c7f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -378,6 +378,7 @@ private: VoxelDetail _mouseVoxel; // details of the voxel to be edited float _mouseVoxelScale; // the scale for adding/removing voxels + bool _mouseVoxelScaleInitialized; glm::vec3 _lastMouseVoxelPos; // the position of the last mouse voxel edit bool _justEditedVoxel; // set when we've just added/deleted/colored a voxel From 359083ee9d48e3818b34520e0e3b2a5e3f850e21 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Nov 2013 12:30:38 -0800 Subject: [PATCH 08/46] Sneak in a toggle for chat circling. --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/MyAvatar.cpp | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0efe582df2..dbae859d24 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -326,6 +326,7 @@ Menu::Menu() : false, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, true); QMenu* webcamOptionsMenu = developerMenu->addMenu("Webcam Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index cf6a35ff2b..987d7ff452 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -146,6 +146,7 @@ namespace MenuOption { const QString AutomaticallyAuditTree = "Automatically Audit Tree Stats"; const QString Bandwidth = "Bandwidth Display"; const QString BandwidthDetails = "Bandwidth Details"; + const QString ChatCircling = "Chat Circling"; const QString Collisions = "Collisions"; const QString CopyVoxels = "Copy"; const QString CoverageMap = "Render Coverage Map"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 99d77f6aff..5ecc806d6f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -17,6 +17,7 @@ #include "Application.h" #include "DataServerClient.h" +#include "Menu.h" #include "MyAvatar.h" #include "Physics.h" #include "devices/OculusManager.h" @@ -1110,6 +1111,10 @@ bool operator<(const SortedAvatar& s1, const SortedAvatar& s2) { } void MyAvatar::updateChatCircle(float deltaTime) { + if (!Menu::getInstance()->isOptionChecked(MenuOption::ChatCircling)) { + return; + } + // find all members and sort by distance QVector sortedAvatars; NodeList* nodeList = NodeList::getInstance(); From e296be8c7ac90b0629bf36e42d8eb7ddf3b87ae4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 12:31:20 -0800 Subject: [PATCH 09/46] make numberOfThreeBitSectionsInCode() robust against overflowing buffers if length is known --- libraries/shared/src/OctalCode.cpp | 9 +++++++-- libraries/shared/src/OctalCode.h | 10 +++++++++- .../src/VoxelServerPacketProcessor.cpp | 10 +++++++++- libraries/voxels/src/VoxelTree.cpp | 9 ++++++++- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index c0f1ccfa62..027a6a4d68 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -16,10 +16,15 @@ #include "SharedUtil.h" #include "OctalCode.h" -int numberOfThreeBitSectionsInCode(const unsigned char* octalCode) { +int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes) { + if (maxBytes == OVERFLOWED_OCTCODE_BUFFER) { + return OVERFLOWED_OCTCODE_BUFFER; + } + assert(octalCode); if (*octalCode == 255) { - return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1); + int newMaxBytes = (maxBytes == UNKNOWN_OCTCODE_LENGTH) ? UNKNOWN_OCTCODE_LENGTH : maxBytes - 1; + return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1, newMaxBytes); } else { return *octalCode; } diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 27746474eb..34d4264de4 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -24,7 +24,15 @@ void printOctalCode(const unsigned char* octalCode); int bytesRequiredForCodeLength(unsigned char threeBitCodes); int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode); unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber); -int numberOfThreeBitSectionsInCode(const unsigned char* octalCode); + +const int OVERFLOWED_OCTCODE_BUFFER = -1; +const int UNKNOWN_OCTCODE_LENGTH = -2; + +/// will return -1 if there is an error in the octcode encoding, or it would overflow maxBytes +/// \param const unsigned char* octalCode the octalcode to decode +/// \param int maxBytes number of bytes that octalCode is expected to be, -1 if unknown +int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH); + unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, bool includeColorSpace = false); diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index 53a6267a7a..a547f441db 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -49,7 +49,15 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned int atByte = numBytesPacketHeader + sizeof(itemNumber); unsigned char* voxelData = (unsigned char*)&packetData[atByte]; while (atByte < packetLength) { - unsigned char octets = numberOfThreeBitSectionsInCode(voxelData); + int maxSize = packetLength - atByte; + unsigned char 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); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index f7f50788c5..57c99c5ff8 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -581,7 +581,14 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe int atByte = sizeof(short int) + numBytesForPacketHeader(bitstream); unsigned char* voxelCode = (unsigned char*)&bitstream[atByte]; while (atByte < bufferSizeBytes) { - int codeLength = numberOfThreeBitSectionsInCode(voxelCode); + int maxSize = bufferSizeBytes - atByte; + unsigned char codeLength = numberOfThreeBitSectionsInCode(voxelCode, maxSize); + + if (codeLength == OVERFLOWED_OCTCODE_BUFFER) { + printf("WARNING! Got remove voxel bitstream that would overflow buffer in numberOfThreeBitSectionsInCode(), "); + printf("bailing processing of packet!\n"); + break; + } int voxelDataSize = bytesRequiredForCodeLength(codeLength) + SIZE_OF_COLOR_DATA; if (atByte + voxelDataSize <= bufferSizeBytes) { From 771021995b512b0f7f49db9869c8e407a9f5fb33 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Nov 2013 12:34:56 -0800 Subject: [PATCH 10/46] add helper to ping with inactive socket --- assignment-client/src/Agent.cpp | 7 +------ libraries/shared/src/NodeList.cpp | 14 ++++++++++---- libraries/shared/src/NodeList.h | 1 + libraries/voxels/src/JurisdictionListener.cpp | 10 ++++++---- libraries/voxels/src/VoxelEditPacketSender.cpp | 10 ++-------- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 1a63d2c4d5..206d115c84 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -171,18 +171,13 @@ void Agent::run() { usleep(usecToSleep); } - if (audioMixer && audioMixer->getActiveSocket() && scriptedAudioInjector.hasSamplesToInject()) { + if (audioMixer && NodeList::getInstance()->getNodeActiveSocketOrPing(audioMixer) && scriptedAudioInjector.hasSamplesToInject()) { // we have an audio mixer and samples to inject, send those off scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getActiveSocket()); // clear out the audio injector so that it doesn't re-send what we just sent scriptedAudioInjector.clear(); } - - if (audioMixer && !audioMixer->getActiveSocket()) { - // don't have an active socket for the audio-mixer, ping it now - NodeList::getInstance()->pingPublicAndLocalSocketsForInactiveNode(audioMixer); - } if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) { // allow the scripter's call back to setup visual data diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 3bf6813465..a943d6dde1 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -687,13 +687,10 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt for(NodeList::iterator node = begin(); node != end(); node++) { // only send to the NodeTypes we are asked to send to. if (memchr(nodeTypes, node->getType(), numNodeTypes)) { - if (node->getActiveSocket()) { + if (getNodeActiveSocketOrPing(&(*node))) { // we know which socket is good for this node, send there _nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes); ++n; - } else { - // we don't have an active link to this node, ping it to set that up - pingPublicAndLocalSocketsForInactiveNode(&(*node)); } } } @@ -718,6 +715,15 @@ void NodeList::possiblyPingInactiveNodes() { } } +sockaddr* NodeList::getNodeActiveSocketOrPing(Node* node) { + if (node->getActiveSocket()) { + return node->getActiveSocket(); + } else { + pingPublicAndLocalSocketsForInactiveNode(node); + return NULL; + } +} + void NodeList::activateSocketFromNodeCommunication(sockaddr *nodeAddress) { for(NodeList::iterator node = begin(); node != end(); node++) { if (!node->getActiveSocket()) { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index c15c37d7bf..47ea2e9e41 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -141,6 +141,7 @@ public: void removeDomainListener(DomainChangeListener* listener); void possiblyPingInactiveNodes(); + sockaddr* getNodeActiveSocketOrPing(Node* node); private: static NodeList* _sharedInstance; diff --git a/libraries/voxels/src/JurisdictionListener.cpp b/libraries/voxels/src/JurisdictionListener.cpp index 4cb946620d..7e259ec689 100644 --- a/libraries/voxels/src/JurisdictionListener.cpp +++ b/libraries/voxels/src/JurisdictionListener.cpp @@ -50,10 +50,12 @@ bool JurisdictionListener::queueJurisdictionRequest() { // only send to the NodeTypes that are interested in our jurisdiction details const int numNodeTypes = 1; const NODE_TYPE nodeTypes[numNodeTypes] = { NODE_TYPE_VOXEL_SERVER }; - if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) { - sockaddr* nodeAddress = node->getActiveSocket(); - PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); - nodeCount++; + if (nodeList->getNodeActiveSocketOrPing(&(*node))) { + if (memchr(nodeTypes, node->getType(), numNodeTypes)) { + sockaddr* nodeAddress = node->getActiveSocket(); + PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); + nodeCount++; + } } } diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 11e4600f6b..8b7c82a4ca 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -90,11 +90,8 @@ bool VoxelEditPacketSender::voxelServersExist() const { for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER if (node->getType() == NODE_TYPE_VOXEL_SERVER) { - if (node->getActiveSocket()) { + if (nodeList->getNodeActiveSocketOrPing(&(*node))) { return true; - } else { - // we don't have an active socket for this node, ping it - nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node)); } } } @@ -109,12 +106,9 @@ void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned ch // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER if (node->getType() == NODE_TYPE_VOXEL_SERVER && ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) { - if (node->getActiveSocket()) { + if (nodeList->getNodeActiveSocketOrPing(&(*node))) { sockaddr* nodeAddress = node->getActiveSocket(); queuePacketForSending(*nodeAddress, buffer, length); - } else { - // we don't have an active socket for this node, ping it - nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node)); } } } From eef6fd53eb5223b92b98685f21280ba70fde5354 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Nov 2013 12:37:38 -0800 Subject: [PATCH 11/46] cleanup node type check in JL --- libraries/voxels/src/JurisdictionListener.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/libraries/voxels/src/JurisdictionListener.cpp b/libraries/voxels/src/JurisdictionListener.cpp index 7e259ec689..6871c881df 100644 --- a/libraries/voxels/src/JurisdictionListener.cpp +++ b/libraries/voxels/src/JurisdictionListener.cpp @@ -46,16 +46,10 @@ bool JurisdictionListener::queueJurisdictionRequest() { NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - - // only send to the NodeTypes that are interested in our jurisdiction details - const int numNodeTypes = 1; - const NODE_TYPE nodeTypes[numNodeTypes] = { NODE_TYPE_VOXEL_SERVER }; - if (nodeList->getNodeActiveSocketOrPing(&(*node))) { - if (memchr(nodeTypes, node->getType(), numNodeTypes)) { - sockaddr* nodeAddress = node->getActiveSocket(); - PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); - nodeCount++; - } + if (nodeList->getNodeActiveSocketOrPing(&(*node)) && node->getType() == NODE_TYPE_VOXEL_SERVER) { + sockaddr* nodeAddress = node->getActiveSocket(); + PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); + nodeCount++; } } From 7cbebf3941d87d01f1cb542f3da536da391b7b45 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 13:11:35 -0800 Subject: [PATCH 12/46] fixed warning and logic problem --- .../voxel-server-library/src/VoxelServerPacketProcessor.cpp | 2 +- libraries/voxels/src/VoxelTree.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index a547f441db..2ade24928a 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -50,7 +50,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned unsigned char* voxelData = (unsigned char*)&packetData[atByte]; while (atByte < packetLength) { int maxSize = packetLength - atByte; - unsigned char octets = numberOfThreeBitSectionsInCode(voxelData, maxSize); + int octets = numberOfThreeBitSectionsInCode(voxelData, maxSize); if (octets == OVERFLOWED_OCTCODE_BUFFER) { printf("WARNING! Got voxel edit record that would overflow buffer in numberOfThreeBitSectionsInCode(), "); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 57c99c5ff8..cfe7828c08 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -582,7 +582,7 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe unsigned char* voxelCode = (unsigned char*)&bitstream[atByte]; while (atByte < bufferSizeBytes) { int maxSize = bufferSizeBytes - atByte; - unsigned char codeLength = numberOfThreeBitSectionsInCode(voxelCode, maxSize); + int codeLength = numberOfThreeBitSectionsInCode(voxelCode, maxSize); if (codeLength == OVERFLOWED_OCTCODE_BUFFER) { printf("WARNING! Got remove voxel bitstream that would overflow buffer in numberOfThreeBitSectionsInCode(), "); From 3ba9c8c30e3e324bb0cf0e50ff623623e0f16312 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 13:41:15 -0800 Subject: [PATCH 13/46] added more debugging --- .../src/VoxelServerPacketProcessor.cpp | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index 2ade24928a..e8b7b9f5c7 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -24,6 +24,12 @@ VoxelServerPacketProcessor::VoxelServerPacketProcessor(VoxelServer* myServer) : void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { + bool debugProcessPacket = true; // temporarily debugging.... + + 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) { @@ -41,7 +47,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned packetLength, itemNumber); } - if (_myServer->wantsDebugVoxelReceiving()) { + if (debugProcessPacket || _myServer->wantsDebugVoxelReceiving()) { printf("got %s - %d command from client receivedBytes=%ld itemNumber=%d\n", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL", _receivedPacketCount, packetLength, itemNumber); @@ -50,6 +56,13 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned 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) { @@ -84,6 +97,12 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned } } + 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* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); if (node) { From 1c580551bbc910e094d8c38821c696002960f4ac Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 13:47:58 -0800 Subject: [PATCH 14/46] added more debugging --- libraries/shared/src/ReceivedPacketProcessor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/shared/src/ReceivedPacketProcessor.cpp b/libraries/shared/src/ReceivedPacketProcessor.cpp index dce65b586e..7e8ffec44f 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.cpp +++ b/libraries/shared/src/ReceivedPacketProcessor.cpp @@ -32,6 +32,10 @@ bool ReceivedPacketProcessor::process() { } while (_packets.size() > 0) { NetworkPacket& packet = _packets.front(); + + printf("ReceivedPacketProcessor::process() calling processPacket() NetworkPacket=%p packet.getData()=%p packet.getLength()=%ld\n", + &packet, packet.getData(), packet.getLength() ); + processPacket(packet.getAddress(), packet.getData(), packet.getLength()); lock(); From 6633b6a633e58c572f7214b0dc02b89d0450d623 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Nov 2013 13:56:14 -0800 Subject: [PATCH 15/46] For now, don't perform avatar collisions unless we have a skeleton model. --- interface/src/avatar/MyAvatar.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5ecc806d6f..7d6877e693 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1060,6 +1060,11 @@ void MyAvatar::updateAvatarCollisions(float deltaTime) { // detect collisions with other avatars and respond void MyAvatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) { + // for now, don't collide if we have a new skeleton + if (_skeletonModel.isActive()) { + return; + } + glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); // loop through the body balls of each avatar to check for every possible collision From 092f1fa4c87dce24f879ca9266ad3c744944c2b6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Nov 2013 14:10:53 -0800 Subject: [PATCH 16/46] Shorten the long term average. --- interface/src/devices/Faceshift.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 4f9670ac50..9a45810cbe 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -68,7 +68,7 @@ void Faceshift::update() { (_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f)))); // compute and subtract the long term average - const float LONG_TERM_AVERAGE_SMOOTHING = 0.9999f; + const float LONG_TERM_AVERAGE_SMOOTHING = 0.999f; if (!_longTermAverageInitialized) { _longTermAverageEyePitch = eulers.x; _longTermAverageEyeYaw = eulers.y; From 406d42fe87b0550330eab426b6c5eff4ccf81132 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 14:27:20 -0800 Subject: [PATCH 17/46] added more debugging --- libraries/shared/src/NetworkPacket.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/NetworkPacket.cpp b/libraries/shared/src/NetworkPacket.cpp index 0acabbac58..6319a5ab1a 100644 --- a/libraries/shared/src/NetworkPacket.cpp +++ b/libraries/shared/src/NetworkPacket.cpp @@ -20,6 +20,7 @@ NetworkPacket::NetworkPacket() { NetworkPacket::~NetworkPacket() { // nothing to do + printf("NetworkPacket::~NetworkPacket() this=%p this.getData()=%p\n", this, getData()); } void NetworkPacket::copyContents(const sockaddr& address, const unsigned char* packetData, ssize_t packetLength) { From add8ccc877814db5c7c4f5f78c70159bcc41b78e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Nov 2013 14:31:41 -0800 Subject: [PATCH 18/46] Lower the deflection amount. --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 908eee237c..46be485fc5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1988,8 +1988,8 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& // deflect using Faceshift gaze data glm::vec3 origin = _myAvatar.getHead().calculateAverageEyePosition(); float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f; - const float PITCH_SCALE = 0.5f; - const float YAW_SCALE = 0.5f; + const float PITCH_SCALE = 0.25f; + const float YAW_SCALE = 0.25f; lookAtSpot = origin + _myCamera.getRotation() * glm::quat(glm::radians(glm::vec3( _faceshift.getEstimatedEyePitch() * pitchSign * PITCH_SCALE, _faceshift.getEstimatedEyeYaw() * YAW_SCALE, 0.0f))) * glm::inverse(_myCamera.getRotation()) * (lookAtSpot - origin); From 318b9b1671e7d3928849a2dcc9fac3c6e55f7151 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 14:50:49 -0800 Subject: [PATCH 19/46] make temp copy of NetworkPacket to protect against vector resizing --- libraries/shared/src/NetworkPacket.cpp | 1 - libraries/shared/src/ReceivedPacketProcessor.cpp | 15 ++++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/libraries/shared/src/NetworkPacket.cpp b/libraries/shared/src/NetworkPacket.cpp index 6319a5ab1a..0acabbac58 100644 --- a/libraries/shared/src/NetworkPacket.cpp +++ b/libraries/shared/src/NetworkPacket.cpp @@ -20,7 +20,6 @@ NetworkPacket::NetworkPacket() { NetworkPacket::~NetworkPacket() { // nothing to do - printf("NetworkPacket::~NetworkPacket() this=%p this.getData()=%p\n", this, getData()); } void NetworkPacket::copyContents(const sockaddr& address, const unsigned char* packetData, ssize_t packetLength) { diff --git a/libraries/shared/src/ReceivedPacketProcessor.cpp b/libraries/shared/src/ReceivedPacketProcessor.cpp index 7e8ffec44f..c1d0a84f0f 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.cpp +++ b/libraries/shared/src/ReceivedPacketProcessor.cpp @@ -31,16 +31,13 @@ bool ReceivedPacketProcessor::process() { usleep(RECEIVED_THREAD_SLEEP_INTERVAL); } while (_packets.size() > 0) { - NetworkPacket& packet = _packets.front(); - printf("ReceivedPacketProcessor::process() calling processPacket() NetworkPacket=%p packet.getData()=%p packet.getLength()=%ld\n", - &packet, packet.getData(), packet.getLength() ); - - processPacket(packet.getAddress(), packet.getData(), packet.getLength()); - - lock(); - _packets.erase(_packets.begin()); - unlock(); + lock(); // lock to make sure nothing changes on us + NetworkPacket& packet = _packets.front(); // get the oldest packet + NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us + _packets.erase(_packets.begin()); // remove the oldest packet + unlock(); // let others add to the packets + processPacket(temporary.getAddress(), temporary.getData(), temporary.getLength()); // process our temporary copy } return isStillRunning(); // keep running till they terminate us } From 93ad1c3f991fb415bffd4f60a8ebab38bb6be91e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 15:11:31 -0800 Subject: [PATCH 20/46] make temp copy of NetworkPacket to protect against vector resizing --- libraries/shared/src/PacketSender.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/shared/src/PacketSender.cpp b/libraries/shared/src/PacketSender.cpp index 0b41a34caf..c03ef21bea 100644 --- a/libraries/shared/src/PacketSender.cpp +++ b/libraries/shared/src/PacketSender.cpp @@ -91,23 +91,23 @@ bool PacketSender::process() { while (keepGoing) { uint64_t SEND_INTERVAL_USECS = (_packetsPerSecond == 0) ? USECS_PER_SECOND : (USECS_PER_SECOND / _packetsPerSecond); + lock(); NetworkPacket& packet = _packets.front(); - + NetworkPacket temporary = packet; // make a copy + _packets.erase(_packets.begin()); + packetsLeft = _packets.size(); + unlock(); + // send the packet through the NodeList... UDPSocket* nodeSocket = NodeList::getInstance()->getNodeSocket(); - nodeSocket->send(&packet.getAddress(), packet.getData(), packet.getLength()); + nodeSocket->send(&temporary.getAddress(), temporary.getData(), temporary.getLength()); packetsThisCall++; if (_notify) { - _notify->packetSentNotification(packet.getLength()); + _notify->packetSentNotification(temporary.getLength()); } - lock(); - _packets.erase(_packets.begin()); - unlock(); - - packetsLeft = _packets.size(); // in threaded mode, we go till we're empty if (isThreaded()) { From 9460fb87c23de9fcf56fbc654d1bc199da819d35 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Nov 2013 16:06:11 -0800 Subject: [PATCH 21/46] Return arm to neutral position when mouse pointer is invisible. --- interface/src/avatar/MyAvatar.cpp | 4 ++++ interface/src/avatar/SkeletonModel.cpp | 7 ++++++- interface/src/renderer/Model.cpp | 20 ++++++++++++++++++++ interface/src/renderer/Model.h | 16 ++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7d6877e693..0a95e78b91 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -831,6 +831,7 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov // reset hand and arm positions according to hand movement glm::vec3 up = orientation * IDENTITY_UP; + bool pointing = false; if (enableHandMovement && glm::length(_mouseRayDirection) > EPSILON && !Application::getInstance()->isMouseHidden()) { // confine to the approximate shoulder plane glm::vec3 pointDirection = _mouseRayDirection; @@ -842,6 +843,7 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov } const float FAR_AWAY_POINT = TREE_SCALE; _skeleton.joint[AVATAR_JOINT_RIGHT_FINGERTIPS].position = _mouseRayOrigin + pointDirection * FAR_AWAY_POINT; + pointing = true; } _avatarTouch.setMyBodyPosition(_position); @@ -933,6 +935,8 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov if (_mousePressed) { _handState = HAND_STATE_GRASPING; + } else if (pointing) { + _handState = HAND_STATE_POINTING; } else { _handState = HAND_STATE_NULL; } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index aa5cb6cfd0..ffc4f1981f 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -28,7 +28,12 @@ void SkeletonModel::simulate(float deltaTime) { Model::simulate(deltaTime); - setRightHandPosition(_owningAvatar->getHandPosition()); + if (_owningAvatar->getHandState() == HAND_STATE_NULL) { + const float HAND_RESTORATION_RATE = 0.25f; + restoreRightHandPosition(HAND_RESTORATION_RATE); + } else { + setRightHandPosition(_owningAvatar->getHandPosition()); + } } bool SkeletonModel::render(float alpha) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 529bd67da8..8867fb2562 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -477,6 +477,10 @@ bool Model::setLeftHandPosition(const glm::vec3& position) { return isActive() && setJointPosition(_geometry->getFBXGeometry().leftHandJointIndex, position); } +bool Model::restoreLeftHandPosition(float percent) { + return isActive() && restoreJointPosition(_geometry->getFBXGeometry().leftHandJointIndex, percent); +} + bool Model::setLeftHandRotation(const glm::quat& rotation) { return isActive() && setJointRotation(_geometry->getFBXGeometry().leftHandJointIndex, rotation); } @@ -485,6 +489,10 @@ bool Model::setRightHandPosition(const glm::vec3& position) { return isActive() && setJointPosition(_geometry->getFBXGeometry().rightHandJointIndex, position); } +bool Model::restoreRightHandPosition(float percent) { + return isActive() && restoreJointPosition(_geometry->getFBXGeometry().rightHandJointIndex, percent); +} + bool Model::setRightHandRotation(const glm::quat& rotation) { return isActive() && setJointRotation(_geometry->getFBXGeometry().rightHandJointIndex, rotation); } @@ -617,6 +625,18 @@ bool Model::setJointRotation(int jointIndex, const glm::quat& rotation) { return true; } +bool Model::restoreJointPosition(int jointIndex, float percent) { + if (jointIndex == -1 || _jointStates.isEmpty()) { + return false; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; + + foreach (int index, freeLineage) { + _jointStates[index].rotation = safeMix(_jointStates[index].rotation, geometry.joints.at(index).rotation, percent); + } +} + void Model::deleteGeometry() { foreach (Model* attachment, _attachments) { delete attachment; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 2c0c553719..f4b07f8242 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -74,6 +74,11 @@ public: /// \return whether or not the left hand joint was found bool setLeftHandPosition(const glm::vec3& position); + /// Restores some percentage of the default position of the left hand. + /// \param percent the percentage of the default position to restore + /// \return whether or not the left hand joint was found + bool restoreLeftHandPosition(float percent = 1.0f); + /// Sets the rotation of the left hand. /// \return whether or not the left hand joint was found bool setLeftHandRotation(const glm::quat& rotation); @@ -82,6 +87,11 @@ public: /// \return whether or not the right hand joint was found bool setRightHandPosition(const glm::vec3& position); + /// Restores some percentage of the default position of the right hand. + /// \param percent the percentage of the default position to restore + /// \return whether or not the right hand joint was found + bool restoreRightHandPosition(float percent = 1.0f); + /// Sets the rotation of the right hand. /// \return whether or not the right hand joint was found bool setRightHandRotation(const glm::quat& rotation); @@ -130,6 +140,12 @@ protected: bool setJointPosition(int jointIndex, const glm::vec3& position); bool setJointRotation(int jointIndex, const glm::quat& rotation); + /// Restores the indexed joint to its default position. + /// \param percent the percentage of the default position to apply (i.e., 0.25f to slerp one fourth of the way to + /// the original position + /// \return true if the joint was found + bool restoreJointPosition(int jointIndex, float percent = 1.0f); + private: void deleteGeometry(); From ae4db63368d9cddd0765c8dea0588598c1b21816 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Nov 2013 16:11:12 -0800 Subject: [PATCH 22/46] Remove growing head behavior. --- interface/src/avatar/Avatar.cpp | 26 -------------------------- interface/src/avatar/Avatar.h | 2 -- 2 files changed, 28 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 1fc2157e09..31e1ee43fb 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -96,8 +96,6 @@ Avatar::Avatar(Node* owningNode) : _leadingAvatar(NULL), _voxels(this), _moving(false), - _hoverOnDuration(0.0f), - _hoverOffDuration(0.0f), _initialized(false), _handHoldingPosition(0.0f, 0.0f, 0.0f), _maxArmLength(0.0f), @@ -387,30 +385,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } } - // head scale grows when avatar is looked at - const float BASE_MAX_SCALE = 3.0f; - float maxScale = BASE_MAX_SCALE * glm::distance(_position, Application::getInstance()->getCamera()->getPosition()); - if (Application::getInstance()->getLookatTargetAvatar() == this) { - _hoverOnDuration += deltaTime; - _hoverOffDuration = 0.0f; - - const float GROW_DELAY = 1.0f; - const float GROW_RATE = 0.25f; - if (_hoverOnDuration > GROW_DELAY) { - _head.setScale(glm::mix(_head.getScale(), maxScale, GROW_RATE)); - } - - } else { - _hoverOnDuration = 0.0f; - _hoverOffDuration += deltaTime; - - const float SHRINK_DELAY = 1.0f; - const float SHRINK_RATE = 0.25f; - if (_hoverOffDuration > SHRINK_DELAY) { - _head.setScale(glm::mix(_head.getScale(), 1.0f, SHRINK_RATE)); - } - } - _skeletonModel.simulate(deltaTime); _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); glm::vec3 headPosition; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 2c54aa4a50..b3c373009f 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -227,8 +227,6 @@ protected: AvatarVoxelSystem _voxels; bool _moving; ///< set when position is changing - float _hoverOnDuration; - float _hoverOffDuration; // protected methods... glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } From c55f8c59003c55c09a2347ec8efda1ab1f416084 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Nov 2013 16:14:21 -0800 Subject: [PATCH 23/46] Forgot to return a value. --- interface/src/renderer/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 8867fb2562..7df5427d91 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -635,6 +635,7 @@ bool Model::restoreJointPosition(int jointIndex, float percent) { foreach (int index, freeLineage) { _jointStates[index].rotation = safeMix(_jointStates[index].rotation, geometry.joints.at(index).rotation, percent); } + return true; } void Model::deleteGeometry() { From 58b74e1f588a61c8c7b90f49b920c4810e4199bb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 5 Nov 2013 20:49:20 -0800 Subject: [PATCH 24/46] added uptime/start time to server status page, and disabled noisy debuggin --- .../voxel-server-library/src/VoxelServer.cpp | 59 ++++++++++++++++++- .../voxel-server-library/src/VoxelServer.h | 3 + .../src/VoxelServerPacketProcessor.cpp | 4 +- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index f77d610980..bfb7022dc0 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -71,7 +72,10 @@ VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assign _voxelServerPacketProcessor = NULL; _voxelPersistThread = NULL; _parsedArgV = NULL; - + + _started = time(0); + _startedUSecs = usecTimestampNow(); + _theInstance = this; } @@ -114,6 +118,45 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "Your Voxel Server is running.\r\n"); + mg_printf(connection, "%s", "\r\n"); + tm* localtm = localtime(&GetInstance()->_started); + const int MAX_TIME_LENGTH = 128; + char buffer[MAX_TIME_LENGTH]; + strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm); + mg_printf(connection, "Running since: %s", buffer); + + // Convert now to tm struct for UTC + tm* gmtm = gmtime(&GetInstance()->_started); + if (gmtm != NULL) { + strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", gmtm); + mg_printf(connection, " [%s UTM] ", buffer); + } + mg_printf(connection, "%s", "\r\n"); + + uint64_t now = usecTimestampNow(); + const int USECS_PER_MSEC = 1000; + uint64_t msecsElapsed = (now - GetInstance()->_startedUSecs) / USECS_PER_MSEC; + const int MSECS_PER_SEC = 1000; + const int SECS_PER_MIN = 60; + const int MIN_PER_HOUR = 60; + const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN; + + float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC; + int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR; + int hours = (msecsElapsed/(MSECS_PER_MIN * MIN_PER_HOUR)); + + mg_printf(connection, "%s", "Uptime: "); + if (hours > 0) { + mg_printf(connection, "%d hour%s ", hours, (hours > 1) ? "s" : "" ); + } + if (minutes > 0) { + mg_printf(connection, "%d minute%s ", minutes, (minutes > 1) ? "s" : ""); + } + if (seconds > 0) { + mg_printf(connection, "%.3f seconds ", seconds); + } + mg_printf(connection, "%s", "\r\n"); + mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "Configuration: \r\n "); @@ -438,7 +481,19 @@ void VoxelServer::run() { _voxelServerPacketProcessor->initialize(true); } - qDebug("Now running...\n"); + // Convert now to tm struct for local timezone + tm* localtm = localtime(&_started); + const int MAX_TIME_LENGTH = 128; + char localBuffer[MAX_TIME_LENGTH] = { 0 }; + char utcBuffer[MAX_TIME_LENGTH] = { 0 }; + strftime(localBuffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm); + // Convert now to tm struct for UTC + tm* gmtm = gmtime(&_started); + if (gmtm != NULL) { + strftime(utcBuffer, MAX_TIME_LENGTH, " [%m/%d/%Y %X UTC]", gmtm); + } + qDebug() << "Now running... started at: " << localBuffer << utcBuffer << "\n"; + // loop to send to nodes requesting data while (true) { diff --git a/libraries/voxel-server-library/src/VoxelServer.h b/libraries/voxel-server-library/src/VoxelServer.h index 81bc68b03d..218205caaf 100644 --- a/libraries/voxel-server-library/src/VoxelServer.h +++ b/libraries/voxel-server-library/src/VoxelServer.h @@ -11,6 +11,7 @@ #define __voxel_server__VoxelServer__ #include +#include #include #include @@ -91,6 +92,8 @@ private: static int civetwebRequestHandler(struct mg_connection *connection); static VoxelServer* _theInstance; + time_t _started; + uint64_t _startedUSecs; }; #endif // __voxel_server__VoxelServer__ diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index e8b7b9f5c7..fea179ca4d 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -24,7 +24,7 @@ VoxelServerPacketProcessor::VoxelServerPacketProcessor(VoxelServer* myServer) : void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { - bool debugProcessPacket = true; // temporarily debugging.... + bool debugProcessPacket = _myServer->wantsDebugVoxelReceiving(); if (debugProcessPacket) { printf("VoxelServerPacketProcessor::processPacket(() packetData=%p packetLength=%ld\n", packetData, packetLength); @@ -47,7 +47,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned packetLength, itemNumber); } - if (debugProcessPacket || _myServer->wantsDebugVoxelReceiving()) { + if (_myServer->wantsDebugVoxelReceiving()) { printf("got %s - %d command from client receivedBytes=%ld itemNumber=%d\n", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL", _receivedPacketCount, packetLength, itemNumber); From c1b22dfdd6a87b226235a7401b41cb39df906448 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 00:00:21 -0800 Subject: [PATCH 25/46] added force_crash to test crashing behavior --- libraries/voxel-server-library/src/VoxelServer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index bfb7022dc0..3072cf9599 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -110,6 +110,17 @@ void VoxelServer::initMongoose(int port) { int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { const struct mg_request_info* ri = mg_get_request_info(connection); + + if (strcmp(ri->uri, "/force_crash") == 0 && strcmp(ri->request_method, "GET") == 0) { + qDebug() << "About to force a crash!\n"; + int foo; + int* forceCrash = &foo; + mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n"); + mg_printf(connection, "%s", "forcing a crash....\r\n"); + delete[] forceCrash; + mg_printf(connection, "%s", "did it crash....\r\n"); + return 1; + } if (strcmp(ri->uri, "/") == 0 && strcmp(ri->request_method, "GET") == 0) { uint64_t checkSum; From 1b18b53cfd84886c52e718550c1c0511f24b6802 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 00:09:37 -0800 Subject: [PATCH 26/46] removed force_crash by default --- libraries/voxel-server-library/src/VoxelServer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 3072cf9599..1053564f3b 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -111,6 +111,7 @@ void VoxelServer::initMongoose(int port) { int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { const struct mg_request_info* ri = mg_get_request_info(connection); +#ifdef FORCE_CRASH if (strcmp(ri->uri, "/force_crash") == 0 && strcmp(ri->request_method, "GET") == 0) { qDebug() << "About to force a crash!\n"; int foo; @@ -121,6 +122,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "did it crash....\r\n"); return 1; } +#endif if (strcmp(ri->uri, "/") == 0 && strcmp(ri->request_method, "GET") == 0) { uint64_t checkSum; From 987ce16b10f8b928d11072040a0dc230b27d3abe Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 01:55:04 -0800 Subject: [PATCH 27/46] more potential fixes for voxel server crashes --- .../src/VoxelServerPacketProcessor.cpp | 2 ++ libraries/voxels/src/JurisdictionSender.cpp | 10 ++++------ libraries/voxels/src/JurisdictionSender.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index fea179ca4d..4b3e870592 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -86,7 +86,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned delete[] vertices; } + _myServer->lockTree(); _myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive); + _myServer->unlockTree(); // skip to next voxel edit record in the packet voxelData += voxelDataSize; diff --git a/libraries/voxels/src/JurisdictionSender.cpp b/libraries/voxels/src/JurisdictionSender.cpp index d00d09b9e9..3d3a3bec6f 100644 --- a/libraries/voxels/src/JurisdictionSender.cpp +++ b/libraries/voxels/src/JurisdictionSender.cpp @@ -35,7 +35,7 @@ void JurisdictionSender::processPacket(sockaddr& senderAddress, unsigned char* if (node) { QUuid nodeUUID = node->getUUID(); lockRequestingNodes(); - _nodesRequestingJurisdictions.insert(nodeUUID); + _nodesRequestingJurisdictions.push(nodeUUID); unlockRequestingNodes(); } } @@ -59,18 +59,16 @@ bool JurisdictionSender::process() { int nodeCount = 0; lockRequestingNodes(); - for (std::set::iterator nodeIterator = _nodesRequestingJurisdictions.begin(); - nodeIterator != _nodesRequestingJurisdictions.end(); nodeIterator++) { + while (!_nodesRequestingJurisdictions.empty()) { - QUuid nodeUUID = *nodeIterator; + QUuid nodeUUID = _nodesRequestingJurisdictions.front(); + _nodesRequestingJurisdictions.pop(); Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID); if (node->getActiveSocket() != NULL) { sockaddr* nodeAddress = node->getActiveSocket(); queuePacketForSending(*nodeAddress, bufferOut, sizeOut); nodeCount++; - // remove it from the set - _nodesRequestingJurisdictions.erase(nodeIterator); } } unlockRequestingNodes(); diff --git a/libraries/voxels/src/JurisdictionSender.h b/libraries/voxels/src/JurisdictionSender.h index 2cf3a6b932..f223621b87 100644 --- a/libraries/voxels/src/JurisdictionSender.h +++ b/libraries/voxels/src/JurisdictionSender.h @@ -11,7 +11,7 @@ #ifndef __shared__JurisdictionSender__ #define __shared__JurisdictionSender__ -#include +#include #include #include @@ -44,6 +44,6 @@ protected: private: pthread_mutex_t _requestingNodeMutex; JurisdictionMap* _jurisdictionMap; - std::set _nodesRequestingJurisdictions; + std::queue _nodesRequestingJurisdictions; }; #endif // __shared__JurisdictionSender__ From ae3364289c0ba4f6be4a2e1e76b9dd2c9778c651 Mon Sep 17 00:00:00 2001 From: Jeroen Baert Date: Wed, 6 Nov 2013 15:02:58 +0100 Subject: [PATCH 28/46] Glibc Linux compilation fix --- assignment-client/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 6088da94e5..900965e405 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -29,7 +29,11 @@ link_hifi_library(voxel-server-library ${TARGET_NAME} ${ROOT_DIR}) include_directories(${ROOT_DIR}/externals/civetweb/include) +if (UNIX) + target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) +endif (UNIX) + # link curl for synchronous script downloads find_package(CURL REQUIRED) include_directories(${CURL_INCLUDE_DIRS}) -target_link_libraries(${TARGET_NAME} ${CURL_LIBRARY}) \ No newline at end of file +target_link_libraries(${TARGET_NAME} ${CURL_LIBRARY}) From 4af5fc0650159b407dbfdb59803cd6600275c4f7 Mon Sep 17 00:00:00 2001 From: Jeroen Baert Date: Wed, 6 Nov 2013 16:03:11 +0100 Subject: [PATCH 29/46] Updated readme file with list of required Ubuntu packages --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 02e241c849..bc32998113 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,9 @@ We have successfully built on OS X 10.8, Ubuntu and a few other modern Linux distributions. A Windows build is planned for the future, but not currently in development. +On a fresh Ubuntu 13.10 install, these are all the packages you need to grab and build the hifi project: +
sudo apt-get install build-essential cmake git libcurl4-openssl-dev libqt5scripttools5 libqt5svg5-dev libqt5webkit5-dev libqt5location5 qtlocation5-dev qtdeclarative5-dev qtscript5-dev qtsensors5-dev qtmultimedia5-dev qtquick1-5-dev libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev
+ Running Interface ----- @@ -147,4 +150,4 @@ To access your local domain in Interface, open your Preferences -- on OS X this If everything worked you should see "Servers: 3" in the upper right. Nice work! In the voxel-server/src directory you will find a README that explains in -further detail how to setup and administer a voxel-server. \ No newline at end of file +further detail how to setup and administer a voxel-server. From 0da28fd44cc6515e453ebd72d9a23d9aa8d88920 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 11:20:40 -0800 Subject: [PATCH 30/46] debbugging for node shutdown in VS --- libraries/voxel-server-library/src/VoxelNodeData.cpp | 12 ++++++++++++ libraries/voxel-server-library/src/VoxelServer.cpp | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 73f0987d97..adaed73a83 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -35,6 +35,8 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _lastVoxelPacketLength = 0; _duplicatePacketCount = 0; resetVoxelPacket(); + + qDebug("VoxelNodeData::VoxelNodeData() this=%p owningNode=%p\n", this, owningNode); } void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { @@ -42,6 +44,10 @@ void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { QUuid nodeUUID = getOwningNode()->getUUID(); _voxelSendThread = new VoxelSendThread(nodeUUID, voxelServer); _voxelSendThread->initialize(true); + + qDebug("VoxelNodeData::initializeVoxelSendThread() this=%p owningNode=%p _voxelSendThread=%p\n", + this, getOwningNode(), _voxelSendThread); + qDebug() << "VoxelNodeData::initializeVoxelSendThread() nodeUUID=" << nodeUUID << "\n"; } bool VoxelNodeData::packetIsDuplicate() const { @@ -111,6 +117,12 @@ void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) { } VoxelNodeData::~VoxelNodeData() { + + qDebug("VoxelNodeData::~VoxelNodeData() this=%p owningNode=%p _voxelSendThread=%p\n", + this, getOwningNode(), _voxelSendThread); + QUuid nodeUUID = getOwningNode()->getUUID(); + qDebug() << "VoxelNodeData::initializeVoxelSendThread() nodeUUID=" << nodeUUID << "\n"; + delete[] _voxelPacket; delete[] _lastVoxelPacket; diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 1053564f3b..04f9f64d70 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -46,7 +46,11 @@ const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxe void attachVoxelNodeDataToNode(Node* newNode) { if (newNode->getLinkedData() == NULL) { - newNode->setLinkedData(new VoxelNodeData(newNode)); + VoxelNodeData* voxelNodeData = new VoxelNodeData(newNode); + QUuid nodeUUID = newNode->getUUID(); + qDebug("attachVoxelNodeDataToNode() newNode=%p voxelNodeData=%p\n", newNode, voxelNodeData); + qDebug() << "attachVoxelNodeDataToNode() node UUID:" << nodeUUID << "\n"; + newNode->setLinkedData(voxelNodeData); } } From 5cd0ecde18b3651f98de73becae4cb72cd27e38d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 12:10:19 -0800 Subject: [PATCH 31/46] small tweak in debug out --- libraries/voxel-server-library/src/VoxelNodeData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index adaed73a83..8151839b7d 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -121,7 +121,7 @@ VoxelNodeData::~VoxelNodeData() { qDebug("VoxelNodeData::~VoxelNodeData() this=%p owningNode=%p _voxelSendThread=%p\n", this, getOwningNode(), _voxelSendThread); QUuid nodeUUID = getOwningNode()->getUUID(); - qDebug() << "VoxelNodeData::initializeVoxelSendThread() nodeUUID=" << nodeUUID << "\n"; + qDebug() << "VoxelNodeData::~VoxelNodeData() nodeUUID=" << nodeUUID << "\n"; delete[] _voxelPacket; delete[] _lastVoxelPacket; From 503de083f8cbc92a9506874612170c6ef480ae18 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Nov 2013 12:27:45 -0800 Subject: [PATCH 32/46] an actual patch for two finger mouselook fail after dialog --- interface/src/Menu.cpp | 124 ++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index dbae859d24..21dfdc247a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -718,16 +719,17 @@ void Menu::aboutApp() { InfoView::forcedShow(); } -void updateDSHostname(const QString& domainServerHostname) { - QString newHostname(DEFAULT_DOMAIN_HOSTNAME); +void sendFakeEnterEvent() { + QPoint lastCursorPosition = QCursor::pos(); - if (domainServerHostname.size() > 0) { - // the user input a new hostname, use that - newHostname = domainServerHostname; + QWindowList windows = QGuiApplication::topLevelWindows(); + foreach(QWindow* window, windows) { + if (window->isActive()) { + QPoint windowPosition = window->mapFromGlobal(lastCursorPosition); + QEnterEvent enterEvent = QEnterEvent(windowPosition, windowPosition, lastCursorPosition); + QCoreApplication::sendEvent(window, &enterEvent); + } } - - // give our nodeList the new domain-server hostname - NodeList::getInstance()->setDomainHostname(newHostname); } const int QLINE_MINIMUM_WIDTH = 400; @@ -743,11 +745,15 @@ void Menu::login() { loginDialog.resize(loginDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, loginDialog.size().height()); int dialogReturn = loginDialog.exec(); + if (dialogReturn == QDialog::Accepted && !loginDialog.textValue().isEmpty() && loginDialog.textValue() != username) { // there has been a username change // ask for a profile reset with the new username Application::getInstance()->resetProfile(loginDialog.textValue()); + } + + sendFakeEnterEvent(); } void Menu::editPreferences() { @@ -811,52 +817,52 @@ void Menu::editPreferences() { layout->addWidget(buttons); int ret = dialog.exec(); - if (ret != QDialog::Accepted) { - return; - } - - QUrl faceModelURL(faceURLEdit->text()); - - if (faceModelURL.toString() != faceURLString) { - // change the faceModelURL in the profile, it will also update this user's BlendFace - applicationInstance->getProfile()->setFaceModelURL(faceModelURL); + if (ret == QDialog::Accepted) { + QUrl faceModelURL(faceURLEdit->text()); - // send the new face mesh URL to the data-server (if we have a client UUID) - DataServerClient::putValueForKey(DataServerKey::FaceMeshURL, - faceModelURL.toString().toLocal8Bit().constData()); - } - - QUrl skeletonModelURL(skeletonURLEdit->text()); - - if (skeletonModelURL.toString() != skeletonURLString) { - // change the skeletonModelURL in the profile, it will also update this user's Body - applicationInstance->getProfile()->setSkeletonModelURL(skeletonModelURL); + if (faceModelURL.toString() != faceURLString) { + // change the faceModelURL in the profile, it will also update this user's BlendFace + applicationInstance->getProfile()->setFaceModelURL(faceModelURL); + + // send the new face mesh URL to the data-server (if we have a client UUID) + DataServerClient::putValueForKey(DataServerKey::FaceMeshURL, + faceModelURL.toString().toLocal8Bit().constData()); + } - // send the new skeleton model URL to the data-server (if we have a client UUID) - DataServerClient::putValueForKey(DataServerKey::SkeletonURL, - skeletonModelURL.toString().toLocal8Bit().constData()); + QUrl skeletonModelURL(skeletonURLEdit->text()); + + if (skeletonModelURL.toString() != skeletonURLString) { + // change the skeletonModelURL in the profile, it will also update this user's Body + applicationInstance->getProfile()->setSkeletonModelURL(skeletonModelURL); + + // send the new skeleton model URL to the data-server (if we have a client UUID) + DataServerClient::putValueForKey(DataServerKey::SkeletonURL, + skeletonModelURL.toString().toLocal8Bit().constData()); + } + + QUrl avatarVoxelURL(avatarURL->text()); + applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL); + + Avatar::sendAvatarURLsMessage(avatarVoxelURL); + + applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum()); + + _maxVoxels = maxVoxels->value(); + applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels); + + applicationInstance->getAvatar()->setLeanScale(leanScale->value()); + + _audioJitterBufferSamples = audioJitterBufferSamples->value(); + + if (_audioJitterBufferSamples != 0) { + applicationInstance->getAudio()->setJitterBufferSamples(_audioJitterBufferSamples); + } + + _fieldOfView = fieldOfView->value(); + applicationInstance->resizeGL(applicationInstance->getGLWidget()->width(), applicationInstance->getGLWidget()->height()); } - QUrl avatarVoxelURL(avatarURL->text()); - applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL); - - Avatar::sendAvatarURLsMessage(avatarVoxelURL); - - applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum()); - - _maxVoxels = maxVoxels->value(); - applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels); - - applicationInstance->getAvatar()->setLeanScale(leanScale->value()); - - _audioJitterBufferSamples = audioJitterBufferSamples->value(); - - if (_audioJitterBufferSamples != 0) { - applicationInstance->getAudio()->setJitterBufferSamples(_audioJitterBufferSamples); - } - - _fieldOfView = fieldOfView->value(); - applicationInstance->resizeGL(applicationInstance->getGLWidget()->width(), applicationInstance->getGLWidget()->height()); + sendFakeEnterEvent(); } void Menu::goToDomain() { @@ -876,9 +882,19 @@ void Menu::goToDomain() { domainDialog.resize(domainDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, domainDialog.size().height()); int dialogReturn = domainDialog.exec(); - if (dialogReturn == QDialog::Accepted && !domainDialog.textValue().isEmpty()) { - updateDSHostname(domainDialog.textValue()); + if (dialogReturn == QDialog::Accepted) { + QString newHostname(DEFAULT_DOMAIN_HOSTNAME); + + if (domainDialog.textValue().size() > 0) { + // the user input a new hostname, use that + newHostname = domainDialog.textValue(); + } + + // give our nodeList the new domain-server hostname + NodeList::getInstance()->setDomainHostname(domainDialog.textValue()); } + + sendFakeEnterEvent(); } void Menu::goToLocation() { @@ -918,6 +934,8 @@ void Menu::goToLocation() { } } } + + sendFakeEnterEvent(); } void Menu::goToUser() { @@ -935,6 +953,8 @@ void Menu::goToUser() { DataServerClient::getValuesForKeysAndUserString((QStringList() << DataServerKey::Domain << DataServerKey::Position), userDialog.textValue()); } + + sendFakeEnterEvent(); } void Menu::bandwidthDetails() { From a4fcff6b19ba8117af9a159a21c9e09a0520873b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Nov 2013 12:36:52 -0800 Subject: [PATCH 33/46] only send fake event to the OGLWidget --- interface/src/Menu.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 21dfdc247a..92c6bbf63b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -721,15 +721,11 @@ void Menu::aboutApp() { void sendFakeEnterEvent() { QPoint lastCursorPosition = QCursor::pos(); + QGLWidget* glWidget = Application::getInstance()->getGLWidget(); - QWindowList windows = QGuiApplication::topLevelWindows(); - foreach(QWindow* window, windows) { - if (window->isActive()) { - QPoint windowPosition = window->mapFromGlobal(lastCursorPosition); - QEnterEvent enterEvent = QEnterEvent(windowPosition, windowPosition, lastCursorPosition); - QCoreApplication::sendEvent(window, &enterEvent); - } - } + QPoint windowPosition = glWidget->mapFromGlobal(lastCursorPosition); + QEnterEvent enterEvent = QEnterEvent(windowPosition, windowPosition, lastCursorPosition); + QCoreApplication::sendEvent(glWidget, &enterEvent); } const int QLINE_MINIMUM_WIDTH = 400; From c3914e648f56c4a73465b56daa8a3f91f426383c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 13:52:31 -0800 Subject: [PATCH 34/46] lock our node while using it to prevent crash on domain shutdown --- .../src/VoxelSendThread.cpp | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 1a7762825c..18f0485983 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -27,27 +27,31 @@ bool VoxelSendThread::process() { uint64_t start = usecTimestampNow(); Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); - VoxelNodeData* nodeData = NULL; if (node) { - nodeData = (VoxelNodeData*) node->getLinkedData(); - } + node->lock(); // make sure the node list doesn't kill our node while we're using it + VoxelNodeData* nodeData = NULL; - int packetsSent = 0; + nodeData = (VoxelNodeData*) 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()) { - printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); + // 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()) { + printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); + } + packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged); } - packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged); + + node->unlock(); // we're done with this node for now. } // dynamically sleep until we need to fire off the next set of voxels int elapsed = (usecTimestampNow() - start); int usecToSleep = VOXEL_SEND_INTERVAL_USECS - elapsed; - + if (usecToSleep > 0) { usleep(usecToSleep); } else { @@ -55,6 +59,7 @@ bool VoxelSendThread::process() { std::cout << "Last send took too much time, not sleeping!\n"; } } + return isStillRunning(); // keep running till they terminate us } From f9291e6e5cae387aecf3ec73c93460eff1475556 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 15:22:17 -0800 Subject: [PATCH 35/46] implement ReadWriteLock for VoxelTree to fix crashes in VoxelServer --- libraries/voxel-server-library/src/VoxelPersistThread.cpp | 6 ++++++ libraries/voxel-server-library/src/VoxelSendThread.cpp | 4 ++-- libraries/voxel-server-library/src/VoxelServer.cpp | 4 ---- libraries/voxel-server-library/src/VoxelServer.h | 3 --- .../src/VoxelServerPacketProcessor.cpp | 8 ++++---- libraries/voxels/src/VoxelTree.h | 8 ++++++++ 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index 75954aacec..0a22b0a2ec 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -33,7 +33,9 @@ bool VoxelPersistThread::process() { { PerformanceWarning warn(true, "Loading Voxel File", true); + _tree->lockForRead(); persistantFileRead = _tree->readFromSVOFile(_filename); + _tree->unlock(); } if (persistantFileRead) { @@ -41,7 +43,9 @@ bool VoxelPersistThread::process() { // after done inserting all these voxels, then reaverage colors qDebug("BEGIN Voxels Re-Averaging\n"); + _tree->lockForWrite(); _tree->reaverageVoxelColors(_tree->rootNode); + _tree->unlock(); qDebug("DONE WITH Voxels Re-Averaging\n"); } @@ -70,7 +74,9 @@ bool VoxelPersistThread::process() { // check the dirty bit and persist here... if (_tree->isDirty()) { qDebug("saving voxels to file %s...\n",_filename); + _tree->lockForRead(); _tree->writeToSVOFile(_filename); + _tree->unlock(); _tree->clearDirtyBit(); // tree is clean after saving qDebug("DONE saving voxels to file...\n"); } diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 18f0485983..9e669b4da7 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -117,7 +117,7 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& /// Version of voxel distributor that sends the deepest LOD level at once int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) { - _myServer->lockTree(); + _myServer->getTree()->lockForRead(); int truePacketsSent = 0; int trueBytesSent = 0; @@ -360,7 +360,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } // end if bag wasn't empty, and so we sent stuff... - _myServer->unlockTree(); + _myServer->getTree()->unlock(); return truePacketsSent; } diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 04f9f64d70..a5cb8f9620 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -343,8 +343,6 @@ void VoxelServer::run() { parsePayload(); } - pthread_mutex_init(&_treeLock, NULL); - qInstallMessageHandler(Logging::verboseMessageHandler); const char* STATUS_PORT = "--statusPort"; @@ -591,8 +589,6 @@ void VoxelServer::run() { // tell our NodeList we're done with notifications nodeList->removeHook(&_nodeWatcher); - - pthread_mutex_destroy(&_treeLock); } diff --git a/libraries/voxel-server-library/src/VoxelServer.h b/libraries/voxel-server-library/src/VoxelServer.h index 218205caaf..ca0b07dd63 100644 --- a/libraries/voxel-server-library/src/VoxelServer.h +++ b/libraries/voxel-server-library/src/VoxelServer.h @@ -48,8 +48,6 @@ public: VoxelTree& getServerTree() { return _serverTree; } JurisdictionMap* getJurisdiction() { return _jurisdiction; } - void lockTree() { pthread_mutex_lock(&_treeLock); } - void unlockTree() { pthread_mutex_unlock(&_treeLock); } VoxelTree* getTree() { return &_serverTree; } int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; } @@ -80,7 +78,6 @@ private: JurisdictionSender* _jurisdictionSender; VoxelServerPacketProcessor* _voxelServerPacketProcessor; VoxelPersistThread* _voxelPersistThread; - pthread_mutex_t _treeLock; EnvironmentData _environmentData[3]; NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index 4b3e870592..d156228544 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -86,9 +86,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned delete[] vertices; } - _myServer->lockTree(); + _myServer->getTree()->lockForWrite(); _myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive); - _myServer->unlockTree(); + _myServer->getTree()->unlock(); // skip to next voxel edit record in the packet voxelData += voxelDataSize; @@ -114,9 +114,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned } else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) { // Send these bits off to the VoxelTree class to process them - _myServer->lockTree(); + _myServer->getTree()->lockForWrite(); _myServer->getServerTree().processRemoveVoxelBitstream((unsigned char*)packetData, packetLength); - _myServer->unlockTree(); + _myServer->getTree()->unlock(); // Make sure our Node and NodeList knows we've heard from this node. Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 933a1f436e..f9a5c38eb9 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -21,6 +21,7 @@ #include "VoxelEditPacketSender.h" #include +#include // Callback function, for recuseTreeWithOperation typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData); @@ -185,6 +186,11 @@ public: // reads voxels from square image with alpha as a Y-axis bool readFromSquareARGB32Pixels(const char *filename); bool readFromSchematicFile(const char* filename); + + // VoxelTree does not currently handle its own locking, caller must use these to lock/unlock + void lockForRead() { lock.lockForRead(); } + void lockForWrite() { lock.lockForWrite(); } + void unlock() { lock.unlock(); } unsigned long getVoxelCount(); @@ -266,6 +272,8 @@ private: static bool nudgeCheck(VoxelNode* node, void* extraData); void nudgeLeaf(VoxelNode* node, void* extraData); void chunkifyLeaf(VoxelNode* node); + + QReadWriteLock lock; }; float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale); From 76ad42015a6afabe4e133e2033e4f4db8b17e1cb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 16:41:08 -0800 Subject: [PATCH 36/46] added debugging to JurisdictionMap for server crashes --- libraries/voxels/src/JurisdictionMap.cpp | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/libraries/voxels/src/JurisdictionMap.cpp b/libraries/voxels/src/JurisdictionMap.cpp index 3da1467f46..c95a71ac75 100644 --- a/libraries/voxels/src/JurisdictionMap.cpp +++ b/libraries/voxels/src/JurisdictionMap.cpp @@ -109,8 +109,47 @@ JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector init(rootOctalCode, endNodes); } +void myDebugoutputBits(unsigned char byte, bool withNewLine) { + if (isalnum(byte)) { + printf("[ %d (%c): ", byte, byte); + } else { + printf("[ %d (0x%x): ", byte, byte); + } + + for (int i = 0; i < 8; i++) { + printf("%d", byte >> (7 - i) & 1); + } + printf(" ] "); + + if (withNewLine) { + printf("\n"); + } +} + + +void myDebugPrintOctalCode(const unsigned char* octalCode, bool withNewLine) { + if (!octalCode) { + printf("NULL"); + } else { + for (int i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) { + myDebugoutputBits(octalCode[i],false); + } + } + if (withNewLine) { + printf("\n"); + } +} + + JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) { + + qDebug("JurisdictionMap::JurisdictionMap(const char* rootHexCode=[%p] %s, const char* endNodesHexCodes=[%p] %s)\n", + rootHexCode, rootHexCode, endNodesHexCodes, endNodesHexCodes); + _rootOctalCode = hexStringToOctalCode(QString(rootHexCode)); + + qDebug("JurisdictionMap::JurisdictionMap() _rootOctalCode=%p octalCode=", _rootOctalCode); + myDebugPrintOctalCode(_rootOctalCode, true); QString endNodesHexStrings(endNodesHexCodes); QString delimiterPattern(","); @@ -120,8 +159,16 @@ JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHe QString endNodeHexString = endNodeList.at(i); unsigned char* endNodeOctcode = hexStringToOctalCode(endNodeHexString); + + qDebug("JurisdictionMap::JurisdictionMap() endNodeList(%d)=%s\n", + i, endNodeHexString.toLocal8Bit().constData()); + //printOctalCode(endNodeOctcode); _endNodes.push_back(endNodeOctcode); + + qDebug("JurisdictionMap::JurisdictionMap() endNodeOctcode=%p octalCode=", endNodeOctcode); + myDebugPrintOctalCode(endNodeOctcode, true); + } } From 100439784d7ca08d68f1b88b60bd109c2d52896d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 6 Nov 2013 17:37:37 -0800 Subject: [PATCH 37/46] got rid of redundant getTree() --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 4 ++-- libraries/voxel-server-library/src/VoxelServer.h | 2 -- .../src/VoxelServerPacketProcessor.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 9e669b4da7..4455f1e379 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -117,7 +117,7 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& /// Version of voxel distributor that sends the deepest LOD level at once int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) { - _myServer->getTree()->lockForRead(); + _myServer->getServerTree().lockForRead(); int truePacketsSent = 0; int trueBytesSent = 0; @@ -360,7 +360,7 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } // end if bag wasn't empty, and so we sent stuff... - _myServer->getTree()->unlock(); + _myServer->getServerTree().unlock(); return truePacketsSent; } diff --git a/libraries/voxel-server-library/src/VoxelServer.h b/libraries/voxel-server-library/src/VoxelServer.h index ca0b07dd63..f938bebd7e 100644 --- a/libraries/voxel-server-library/src/VoxelServer.h +++ b/libraries/voxel-server-library/src/VoxelServer.h @@ -48,8 +48,6 @@ public: VoxelTree& getServerTree() { return _serverTree; } JurisdictionMap* getJurisdiction() { return _jurisdiction; } - VoxelTree* getTree() { return &_serverTree; } - int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; } bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; } EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; } diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index d156228544..5fd2028f50 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -86,9 +86,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned delete[] vertices; } - _myServer->getTree()->lockForWrite(); + _myServer->getServerTree().lockForWrite(); _myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive); - _myServer->getTree()->unlock(); + _myServer->getServerTree().unlock(); // skip to next voxel edit record in the packet voxelData += voxelDataSize; @@ -114,9 +114,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned } else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) { // Send these bits off to the VoxelTree class to process them - _myServer->getTree()->lockForWrite(); + _myServer->getServerTree().lockForWrite(); _myServer->getServerTree().processRemoveVoxelBitstream((unsigned char*)packetData, packetLength); - _myServer->getTree()->unlock(); + _myServer->getServerTree().unlock(); // Make sure our Node and NodeList knows we've heard from this node. Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); From 4cbb98028f34ddcb5fd5aa068887fd64c68c0059 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Nov 2013 12:07:34 -0800 Subject: [PATCH 38/46] temp remove audio from agent, fix GOL placeholder --- assignment-client/src/Agent.cpp | 29 +++++-------------- .../resources/web/assignment/placeholder.js | 5 ++++ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 206d115c84..4319ca706e 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -57,7 +57,7 @@ void Agent::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AGENT); - const char AGENT_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER }; + const char AGENT_NODE_TYPES_OF_INTEREST[1] = { NODE_TYPE_VOXEL_SERVER }; nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST)); @@ -114,9 +114,11 @@ void Agent::run() { QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); + + const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; // let the VoxelPacketSender know how frequently we plan to call it - voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(INJECT_INTERVAL_USECS); + voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); // hook in a constructor for audio injectorss AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); @@ -158,28 +160,14 @@ void Agent::run() { NodeList::getInstance()->sendDomainServerCheckIn(); } - // find the audio-mixer in the NodeList so we can inject audio at it - Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); - - - if (audioMixer && audioMixer->getActiveSocket()) { - emit willSendAudioDataCallback(); - } - - int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); + int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); } - if (audioMixer && NodeList::getInstance()->getNodeActiveSocketOrPing(audioMixer) && scriptedAudioInjector.hasSamplesToInject()) { - // we have an audio mixer and samples to inject, send those off - scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getActiveSocket()); - - // clear out the audio injector so that it doesn't re-send what we just sent - scriptedAudioInjector.clear(); - } - if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) { + timeval thisSend = {}; + gettimeofday(&thisSend, NULL); // allow the scripter's call back to setup visual data emit willSendVisualDataCallback(); @@ -188,14 +176,13 @@ void Agent::run() { // since we're in non-threaded mode, call process so that the packets are sent voxelScripter.getVoxelPacketSender()->process(); - } if (engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; } - + while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes) && packetVersionMatch(receivedData)) { if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { diff --git a/domain-server/resources/web/assignment/placeholder.js b/domain-server/resources/web/assignment/placeholder.js index 74891d12e8..ee8f89cdd6 100644 --- a/domain-server/resources/web/assignment/placeholder.js +++ b/domain-server/resources/web/assignment/placeholder.js @@ -78,6 +78,11 @@ function updateCells() { nextCells[i][j] = -1; } } + + if (Math.random() < 0.001) { + // Random mutation to keep things interesting in there. + nextCells[i][j] = 1; + } } } From fe962e6be1708facb37ea4182eff27cf8f439d9c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Nov 2013 12:38:28 -0800 Subject: [PATCH 39/46] only call deleteLater for linkedData if we have a QCoreApplication instance --- assignment-client/src/main.cpp | 5 ----- libraries/shared/src/Node.cpp | 5 ++++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index c866f5f00c..728bcb3c00 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -12,9 +12,6 @@ #include #include -#include - - #include #include #include @@ -41,8 +38,6 @@ int argc = 0; char** argv = NULL; void childClient() { - QCoreApplication application(::argc, ::argv); - // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(CHILD_TARGET_NAME); diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index 093f479c48..e62dc2fd53 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -21,6 +21,7 @@ #include "SharedUtil.h" #include "UDPSocket.h" +#include #include Node::Node(const QUuid& uuid, char type, sockaddr* publicSocket, sockaddr* localSocket) : @@ -43,8 +44,10 @@ Node::~Node() { delete _publicSocket; delete _localSocket; - if (_linkedData) { + if (QCoreApplication::instance()) { _linkedData->deleteLater(); + } else { + delete _linkedData; } delete _bytesReceivedMovingAverage; From 24c88512e2f1e06bf3f9d81aa46d909f64d6a23f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Nov 2013 12:41:29 -0800 Subject: [PATCH 40/46] only attempt to deleteLater on linkedData if it exists --- libraries/shared/src/Node.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index e62dc2fd53..205d3109a5 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -45,7 +45,9 @@ Node::~Node() { delete _localSocket; if (QCoreApplication::instance()) { - _linkedData->deleteLater(); + if (_linkedData) { + _linkedData->deleteLater(); + } } else { delete _linkedData; } From b5f6a51728919ba82b8320d26d0a33d3d53d6227 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Nov 2013 13:03:04 -0800 Subject: [PATCH 41/46] fix thread contention issues and VS crash on domain server shutdown and restart --- .../src/VoxelNodeData.cpp | 1 + .../voxel-server-library/src/VoxelNodeData.h | 2 +- .../src/VoxelPersistThread.cpp | 29 ++++----- .../src/VoxelPersistThread.h | 11 +++- .../src/VoxelSendThread.cpp | 44 ++++++++------ .../voxel-server-library/src/VoxelServer.cpp | 59 ++++++++++++++++++- .../voxel-server-library/src/VoxelServer.h | 4 ++ .../src/VoxelServerPacketProcessor.cpp | 2 +- libraries/voxels/src/VoxelQuery.cpp | 1 + libraries/voxels/src/VoxelQuery.h | 2 +- libraries/voxels/src/VoxelTree.cpp | 3 +- libraries/voxels/src/VoxelTree.h | 2 + 12 files changed, 116 insertions(+), 44 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 8151839b7d..2cede147b3 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -129,6 +129,7 @@ VoxelNodeData::~VoxelNodeData() { if (_voxelSendThread) { _voxelSendThread->terminate(); delete _voxelSendThread; + qDebug("VoxelNodeData::~VoxelNodeData() DELETED _voxelSendThread=%p\n", _voxelSendThread); } } diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index 1ad4558b81..c21b99a308 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -24,7 +24,7 @@ class VoxelServer; class VoxelNodeData : public VoxelQuery { public: VoxelNodeData(Node* owningNode); - ~VoxelNodeData(); + virtual ~VoxelNodeData(); void resetVoxelPacket(); // resets voxel packet to after "V" header diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index 0a22b0a2ec..0f2718fe1f 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -20,34 +20,28 @@ VoxelPersistThread::VoxelPersistThread(VoxelTree* tree, const char* filename, in _tree(tree), _filename(filename), _persistInterval(persistInterval), - _initialLoad(false) { + _initialLoadComplete(false), + _loadTimeUSecs(0) { } bool VoxelPersistThread::process() { - if (!_initialLoad) { - _initialLoad = true; + if (!_initialLoadComplete) { + uint64_t loadStarted = usecTimestampNow(); qDebug("loading voxels from file: %s...\n", _filename); bool persistantFileRead; - + + _tree->lockForWrite(); { PerformanceWarning warn(true, "Loading Voxel File", true); - _tree->lockForRead(); persistantFileRead = _tree->readFromSVOFile(_filename); - _tree->unlock(); } + _tree->unlock(); - if (persistantFileRead) { - PerformanceWarning warn(true, "Voxels Re-Averaging", true); - - // after done inserting all these voxels, then reaverage colors - qDebug("BEGIN Voxels Re-Averaging\n"); - _tree->lockForWrite(); - _tree->reaverageVoxelColors(_tree->rootNode); - _tree->unlock(); - qDebug("DONE WITH Voxels Re-Averaging\n"); - } + _loadCompleted = time(0); + uint64_t loadDone = usecTimestampNow(); + _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)); @@ -65,6 +59,7 @@ bool VoxelPersistThread::process() { qDebug("setChildAtIndexCalls=%llu setChildAtIndexTime=%llu perSet=%lf\n", VoxelNode::getSetChildAtIndexTime(), VoxelNode::getSetChildAtIndexCalls(), usecPerSet); + _initialLoadComplete = true; } uint64_t MSECS_TO_USECS = 1000; @@ -74,9 +69,7 @@ bool VoxelPersistThread::process() { // check the dirty bit and persist here... if (_tree->isDirty()) { qDebug("saving voxels to file %s...\n",_filename); - _tree->lockForRead(); _tree->writeToSVOFile(_filename); - _tree->unlock(); _tree->clearDirtyBit(); // tree is clean after saving qDebug("DONE saving voxels to file...\n"); } diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.h b/libraries/voxel-server-library/src/VoxelPersistThread.h index 3219633702..91e65a2daf 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.h +++ b/libraries/voxel-server-library/src/VoxelPersistThread.h @@ -21,6 +21,12 @@ public: static const int DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds VoxelPersistThread(VoxelTree* tree, const char* filename, int persistInterval = DEFAULT_PERSIST_INTERVAL); + + bool isInitialLoadComplete() const { return _initialLoadComplete; } + + time_t* getLoadCompleted() { return &_loadCompleted; } + uint64_t getLoadElapsedTime() const { return _loadTimeUSecs; } + protected: /// Implements generic processing behavior for this thread. virtual bool process(); @@ -28,7 +34,10 @@ private: VoxelTree* _tree; const char* _filename; int _persistInterval; - bool _initialLoad; + bool _initialLoadComplete; + + time_t _loadCompleted; + uint64_t _loadTimeUSecs; }; #endif // __voxel_server__VoxelPersistThread__ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 4455f1e379..4bfed9c9ad 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -26,28 +26,35 @@ VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) : bool VoxelSendThread::process() { uint64_t start = usecTimestampNow(); - Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); + // don't do any send processing until the initial load of the voxels is complete... + if (_myServer->isInitialLoadComplete()) { + Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); - if (node) { - node->lock(); // make sure the node list doesn't kill our node while we're using it - VoxelNodeData* nodeData = NULL; + if (node) { + node->lock(); // make sure the node list doesn't kill our node while we're using it + VoxelNodeData* nodeData = NULL; - nodeData = (VoxelNodeData*) node->getLinkedData(); + nodeData = (VoxelNodeData*) node->getLinkedData(); - int packetsSent = 0; + 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()) { - printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); + // 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()) { + printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); + } + packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged); } - packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged); + + node->unlock(); // we're done with this node for now. + } + } else { + if (_myServer->wantsDebugVoxelSending()) { + qDebug("VoxelSendThread::process() waiting for isInitialLoadComplete()\n"); } - - node->unlock(); // we're done with this node for now. } - + // dynamically sleep until we need to fire off the next set of voxels int elapsed = (usecTimestampNow() - start); int usecToSleep = VOXEL_SEND_INTERVAL_USECS - elapsed; @@ -117,8 +124,6 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& /// Version of voxel distributor that sends the deepest LOD level at once int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) { - _myServer->getServerTree().lockForRead(); - int truePacketsSent = 0; int trueBytesSent = 0; int packetsSentThisInterval = 0; @@ -289,10 +294,13 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction()); + + _myServer->getServerTree().lockForRead(); nodeData->stats.encodeStarted(); bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, nodeData->nodeBag, params); nodeData->stats.encodeStopped(); + _myServer->getServerTree().unlock(); if (nodeData->getAvailable() >= bytesWritten) { nodeData->writeToPacket(_tempOutputBuffer, bytesWritten); @@ -360,8 +368,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod } // end if bag wasn't empty, and so we sent stuff... - _myServer->getServerTree().unlock(); - return truePacketsSent; } diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index a5cb8f9620..88fed0e921 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -175,6 +175,47 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "\r\n"); + + // display voxel file load time + if (GetInstance()->isInitialLoadComplete()) { + tm* voxelsLoadedAtLocal = localtime(GetInstance()->getLoadCompleted()); + 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); + + // Convert now to tm struct for UTC + tm* voxelsLoadedAtUTM = gmtime(GetInstance()->getLoadCompleted()); + if (gmtm != NULL) { + strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", voxelsLoadedAtUTM); + mg_printf(connection, " [%s UTM] ", buffer); + } + mg_printf(connection, "%s", "\r\n"); + + + uint64_t msecsElapsed = GetInstance()->getLoadElapsedTime() / USECS_PER_MSEC;; + float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC; + 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: "); + if (hours > 0) { + mg_printf(connection, "%d hour%s ", hours, (hours > 1) ? "s" : "" ); + } + if (minutes > 0) { + mg_printf(connection, "%d minute%s ", minutes, (minutes > 1) ? "s" : ""); + } + if (seconds > 0) { + mg_printf(connection, "%.3f seconds", seconds); + } + mg_printf(connection, "%s", "\r\n"); + + } else { + mg_printf(connection, "%s", "Voxels not yet loaded...\r\n"); + } + + mg_printf(connection, "%s", "\r\n"); + mg_printf(connection, "%s", "\r\n"); mg_printf(connection, "%s", "Configuration: \r\n "); for (int i = 1; i < GetInstance()->_argc; i++) { @@ -512,14 +553,15 @@ void VoxelServer::run() { // loop to send to nodes requesting data while (true) { - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + qDebug() << "Exit loop... getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS\n"; break; } // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); + //qDebug() << "VoxelServer::run()... NodeList::getInstance()->sendDomainServerCheckIn()\n"; NodeList::getInstance()->sendDomainServerCheckIn(); } @@ -569,26 +611,39 @@ void VoxelServer::run() { } } } + qDebug() << "VoxelServer::run()... AFTER loop...\n"; - delete _jurisdiction; + // call NodeList::clear() so that all of our node specific objects, including our sending threads, are + // properly shutdown and cleaned up. + NodeList::getInstance()->clear(); + qDebug() << "VoxelServer::run()... terminating _jurisdictionSender\n"; if (_jurisdictionSender) { _jurisdictionSender->terminate(); delete _jurisdictionSender; } + qDebug() << "VoxelServer::run()... terminating _voxelServerPacketProcessor\n"; if (_voxelServerPacketProcessor) { _voxelServerPacketProcessor->terminate(); delete _voxelServerPacketProcessor; } + qDebug() << "VoxelServer::run()... terminating _voxelPersistThread\n"; if (_voxelPersistThread) { _voxelPersistThread->terminate(); delete _voxelPersistThread; } // tell our NodeList we're done with notifications + qDebug() << "VoxelServer::run()... nodeList->removeHook(&_nodeWatcher)\n"; nodeList->removeHook(&_nodeWatcher); + + qDebug() << "VoxelServer::run()... deleting _jurisdiction\n"; + delete _jurisdiction; + _jurisdiction = NULL; + + qDebug() << "VoxelServer::run()... DONE\n"; } diff --git a/libraries/voxel-server-library/src/VoxelServer.h b/libraries/voxel-server-library/src/VoxelServer.h index f938bebd7e..92590489f8 100644 --- a/libraries/voxel-server-library/src/VoxelServer.h +++ b/libraries/voxel-server-library/src/VoxelServer.h @@ -55,6 +55,10 @@ public: 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; } + private: int _argc; const char** _argv; diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index 5fd2028f50..672c4f0d50 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -85,7 +85,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned printf("inserting voxel: %f,%f,%f r=%d,g=%d,b=%d\n", vertices[0], vertices[1], vertices[2], red, green, blue); delete[] vertices; } - + _myServer->getServerTree().lockForWrite(); _myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive); _myServer->getServerTree().unlock(); diff --git a/libraries/voxels/src/VoxelQuery.cpp b/libraries/voxels/src/VoxelQuery.cpp index 463b806eba..9b5d65e0c5 100644 --- a/libraries/voxels/src/VoxelQuery.cpp +++ b/libraries/voxels/src/VoxelQuery.cpp @@ -42,6 +42,7 @@ VoxelQuery::VoxelQuery(Node* owningNode) : } VoxelQuery::~VoxelQuery() { + qDebug("VoxelQuery::~VoxelQuery()\n"); } int VoxelQuery::getBroadcastData(unsigned char* destinationBuffer) { diff --git a/libraries/voxels/src/VoxelQuery.h b/libraries/voxels/src/VoxelQuery.h index bedbfdac4e..c95b632eef 100644 --- a/libraries/voxels/src/VoxelQuery.h +++ b/libraries/voxels/src/VoxelQuery.h @@ -35,7 +35,7 @@ class VoxelQuery : public NodeData { public: VoxelQuery(Node* owningNode = NULL); - ~VoxelQuery(); + virtual ~VoxelQuery(); int getBroadcastData(unsigned char* destinationBuffer); int parseData(unsigned char* sourceBuffer, int numBytes); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index cfe7828c08..e0e1ac5367 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1806,9 +1806,10 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) { while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); + lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); - + unlock(); file.write((const char*)&outputBuffer[0], bytesWritten); } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index f9a5c38eb9..f8e0458fa1 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -189,7 +189,9 @@ public: // VoxelTree does not currently handle its own locking, caller must use these to lock/unlock void lockForRead() { lock.lockForRead(); } + void tryLockForRead() { lock.tryLockForRead(); } void lockForWrite() { lock.lockForWrite(); } + void tryLockForWrite() { lock.tryLockForWrite(); } void unlock() { lock.unlock(); } unsigned long getVoxelCount(); From 77ba88e56dbfaae9157e761c4d8bf234de8f9581 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Nov 2013 13:06:57 -0800 Subject: [PATCH 42/46] removed dead comment --- libraries/voxel-server-library/src/VoxelServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 88fed0e921..de421341f3 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -561,7 +561,6 @@ void VoxelServer::run() { // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); - //qDebug() << "VoxelServer::run()... NodeList::getInstance()->sendDomainServerCheckIn()\n"; NodeList::getInstance()->sendDomainServerCheckIn(); } From 64d5ccf91e7e29dc1d43a4a7450d8feac9d6f98a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 7 Nov 2013 14:10:09 -0800 Subject: [PATCH 43/46] add menu option for voxel server fade in/out and dont remove local voxels when server shuts down --- interface/src/Application.cpp | 24 ++++++++++++++---------- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/VoxelSystem.cpp | 15 --------------- 4 files changed, 16 insertions(+), 25 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 46be485fc5..fbf383cc6f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4094,11 +4094,13 @@ void Application::nodeKilled(Node* node) { rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); // Add the jurisditionDetails object to the list of "fade outs" - VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE); - fade.voxelDetails = rootDetails; - const float slightly_smaller = 0.99; - fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; - _voxelFades.push_back(fade); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnVoxelServerChanges)) { + VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE); + fade.voxelDetails = rootDetails; + const float slightly_smaller = 0.99; + fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; + _voxelFades.push_back(fade); + } } } else if (node->getLinkedData() == _lookatTargetAvatar) { _lookatTargetAvatar = NULL; @@ -4127,11 +4129,13 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); // Add the jurisditionDetails object to the list of "fade outs" - VoxelFade fade(VoxelFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE); - fade.voxelDetails = rootDetails; - const float slightly_smaller = 0.99; - fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; - _voxelFades.push_back(fade); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnVoxelServerChanges)) { + VoxelFade fade(VoxelFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE); + fade.voxelDetails = rootDetails; + const float slightly_smaller = 0.99; + fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; + _voxelFades.push_back(fade); + } } // store jurisdiction details for later use // This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 92c6bbf63b..3d1b7b7bf1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -283,6 +283,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges); addActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); QMenu* cullingOptionsMenu = voxelOptionsMenu->addMenu("Culling Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 987d7ff452..30ef055447 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -165,6 +165,7 @@ namespace MenuOption { const QString EchoAudio = "Echo Audio"; const QString ExportVoxels = "Export Voxels"; const QString ExtraDebugging = "Extra Debugging"; + const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString HeadMouse = "Head Mouse"; const QString FaceMode = "Cycle Face Mode"; const QString FaceshiftTCP = "Faceshift (TCP)"; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 1219548b4d..62419565c6 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -2645,23 +2645,8 @@ bool VoxelSystem::killSourceVoxelsOperation(VoxelNode* node, void* extraData) { void VoxelSystem::nodeKilled(Node* node) { if (node->getType() == NODE_TYPE_VOXEL_SERVER) { _voxelServerCount--; - QUuid nodeUUID = node->getUUID(); - qDebug("VoxelSystem... voxel server %s removed...\n", nodeUUID.toString().toLocal8Bit().constData()); - - if (_voxelServerCount > 0) { - // Kill any voxels from the local tree that match this nodeID - // commenting out for removal of 16 bit node IDs - lockTree(); - _tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeUUID); - unlockTree(); - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); - } else { - // Last server, take the easy way and kill all the local voxels! - killLocalVoxels(); - } } } From 9aacda7d56ce20f2de9ade4532398a1ecdf77726 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Nov 2013 14:34:01 -0800 Subject: [PATCH 44/46] fix for AC lack of QCoreApplication --- assignment-client/src/main.cpp | 2 ++ libraries/shared/src/Node.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 728bcb3c00..10b32f901f 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -38,6 +38,8 @@ int argc = 0; char** argv = NULL; void childClient() { + QCoreApplication(::argc, ::argv); + // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(CHILD_TARGET_NAME); diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index 205d3109a5..dcdc0eacca 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -45,6 +45,8 @@ Node::~Node() { delete _localSocket; if (QCoreApplication::instance()) { + // even if we have a QCoreApplication instance we don't get here unless it's been exec'ed + // which is only currently the case for interface if (_linkedData) { _linkedData->deleteLater(); } From ce52395a083c23cb68aa5b642f740f7fd82317ac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Nov 2013 15:06:11 -0800 Subject: [PATCH 45/46] actually create the QCoreApplication instance --- assignment-client/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 10b32f901f..6f8cd83784 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -38,7 +38,7 @@ int argc = 0; char** argv = NULL; void childClient() { - QCoreApplication(::argc, ::argv); + QCoreApplication application(::argc, ::argv); // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(CHILD_TARGET_NAME); From 5889d4122f83396026285536ee316561aa666601 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Nov 2013 15:41:10 -0800 Subject: [PATCH 46/46] use virtual deleteOrDeleteLater in NodeData to handle AvatarVoxelSystem --- interface/src/avatar/Avatar.cpp | 5 +++++ interface/src/avatar/Avatar.h | 1 + libraries/shared/src/Node.cpp | 11 ++--------- libraries/shared/src/NodeData.cpp | 4 ++++ libraries/shared/src/NodeData.h | 2 ++ 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 31e1ee43fb..2359ea2460 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -255,6 +255,11 @@ Avatar::~Avatar() { delete _balls; } +void Avatar::deleteOrDeleteLater() { + this->deleteLater(); +} + + void Avatar::init() { _head.init(); _hand.init(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index b3c373009f..4258ce6f14 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -134,6 +134,7 @@ public: Avatar(Node* owningNode = NULL); ~Avatar(); + void deleteOrDeleteLater(); void init(); void simulate(float deltaTime, Transmitter* transmitter); diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index dcdc0eacca..d4bd8a084a 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -21,7 +21,6 @@ #include "SharedUtil.h" #include "UDPSocket.h" -#include #include Node::Node(const QUuid& uuid, char type, sockaddr* publicSocket, sockaddr* localSocket) : @@ -44,14 +43,8 @@ Node::~Node() { delete _publicSocket; delete _localSocket; - if (QCoreApplication::instance()) { - // even if we have a QCoreApplication instance we don't get here unless it's been exec'ed - // which is only currently the case for interface - if (_linkedData) { - _linkedData->deleteLater(); - } - } else { - delete _linkedData; + if (_linkedData) { + _linkedData->deleteOrDeleteLater(); } delete _bytesReceivedMovingAverage; diff --git a/libraries/shared/src/NodeData.cpp b/libraries/shared/src/NodeData.cpp index 45e8357d4f..6ab7f2242b 100644 --- a/libraries/shared/src/NodeData.cpp +++ b/libraries/shared/src/NodeData.cpp @@ -16,4 +16,8 @@ NodeData::NodeData(Node* owningNode) : NodeData::~NodeData() { +} + +void NodeData::deleteOrDeleteLater() { + delete this; } \ No newline at end of file diff --git a/libraries/shared/src/NodeData.h b/libraries/shared/src/NodeData.h index e92656f977..0a2ba3b514 100644 --- a/libraries/shared/src/NodeData.h +++ b/libraries/shared/src/NodeData.h @@ -21,6 +21,8 @@ public: virtual ~NodeData() = 0; virtual int parseData(unsigned char* sourceBuffer, int numBytes) = 0; + virtual void deleteOrDeleteLater(); + Node* getOwningNode() { return _owningNode; } protected: Node* _owningNode;