diff --git a/.eslintrc.js b/.eslintrc.js index 54ff0a1268..5667a04984 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -68,7 +68,7 @@ module.exports = { "eqeqeq": ["error", "always"], "indent": ["error", 4, { "SwitchCase": 1 }], "keyword-spacing": ["error", { "before": true, "after": true }], - "max-len": ["error", 192, 4], + "max-len": ["error", 128, 4], "new-cap": ["error"], "no-floating-decimal": ["error"], //"no-magic-numbers": ["error", { "ignore": [0, 1], "ignoreArrayIndexes": true }], diff --git a/.gitignore b/.gitignore index 072e6001da..c1eef3817f 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,10 @@ gvr-interface/libs/* # ignore files for various dev environments TAGS *.sw[po] +*.qmlc + +# ignore QML compilation output +*.qmlc # ignore node files for the console node_modules diff --git a/README.md b/README.md index 6294981e9a..e0bbed3105 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,10 @@ Documentation is available at [docs.highfidelity.com](https://docs.highfidelity. There is also detailed [documentation on our coding standards](https://wiki.highfidelity.com/wiki/Coding_Standards). +Contributor License Agreement (CLA) +========= +Technology companies frequently receive and use code from contributors outside the company's development team. Outside code can be a tremendous resource, but it also carries responsibility. Best practice for accepting outside contributions consists of an Apache-type Contributor License Agreement (CLA). We have modeled the High Fidelity CLA after the CLA that Google presents to developers for contributions to their projects. This CLA does not transfer ownership of code, instead simply granting a non-exclusive right for High Fidelity to use the code you’ve contributed. In that regard, you should be sure you have permission if the work relates to or uses the resources of a company that you work for. You will be asked to sign our CLA when you create your first PR or when the CLA is updated. You can also [review it here](https://gist.githubusercontent.com/hifi-gustavo/fef8f06a8233d42a0040d45c3efb97a9/raw/9981827eb94f0b18666083670b6f6a02929fb402/High%2520Fidelity%2520CLA). We sincerely appreciate your contribution and efforts toward the success of the platform. + Build Instructions ========= All information required to build is found in the [build guide](BUILD.md). diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 5539d6a0bb..1868ccfafe 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -28,6 +28,10 @@ const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; const int WAIT_FOR_CHILD_MSECS = 1000; +#ifdef Q_OS_WIN +HANDLE PROCESS_GROUP = createProcessGroup(); +#endif + AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, @@ -202,6 +206,10 @@ void AssignmentClientMonitor::spawnChildClient() { assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels); assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments); +#ifdef Q_OS_WIN + addProcessToGroup(PROCESS_GROUP, assignmentClient->processId()); +#endif + QString stdoutPath, stderrPath; if (_wantsChildFileLogging) { diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index e7d86c824e..ca0f222e0c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -50,9 +50,9 @@ static const int INTERFACE_RUNNING_CHECK_FREQUENCY_MS = 1000; const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; -static const QStringList BAKEABLE_MODEL_EXTENSIONS = {"fbx"}; +static const QStringList BAKEABLE_MODEL_EXTENSIONS = { "fbx" }; static QStringList BAKEABLE_TEXTURE_EXTENSIONS; -static const QStringList BAKEABLE_SCRIPT_EXTENSIONS = {"js"}; +static const QStringList BAKEABLE_SCRIPT_EXTENSIONS = {}; static const QString BAKED_MODEL_SIMPLE_NAME = "asset.fbx"; static const QString BAKED_TEXTURE_SIMPLE_NAME = "texture.ktx"; static const QString BAKED_SCRIPT_SIMPLE_NAME = "asset.js"; diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9ed6c7fdbc..7f088d8183 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -29,6 +29,7 @@ #include #include +#include "AudioLogging.h" #include "AudioHelpers.h" #include "AudioRingBuffer.h" #include "AudioMixerClientData.h" @@ -130,7 +131,7 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess PacketType rewrittenType = PacketTypeEnum::getReplicatedPacketMapping().key(message->getType()); if (rewrittenType == PacketType::Unknown) { - qDebug() << "Cannot unwrap replicated packet type not present in REPLICATED_PACKET_WRAPPING"; + qCDebug(audio) << "Cannot unwrap replicated packet type not present in REPLICATED_PACKET_WRAPPING"; } auto replicatedMessage = QSharedPointer::create(audioData, rewrittenType, @@ -345,7 +346,7 @@ void AudioMixer::sendStatsPacket() { void AudioMixer::run() { - qDebug() << "Waiting for connection to domain to request settings from domain-server."; + qCDebug(audio) << "Waiting for connection to domain to request settings from domain-server."; // wait until we have the domain-server settings, otherwise we bail DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); @@ -502,14 +503,14 @@ void AudioMixer::throttle(std::chrono::microseconds duration, int frame) { int proportionalTerm = 1 + (_trailingMixRatio - TARGET) / 0.1f; _throttlingRatio += THROTTLE_RATE * proportionalTerm; _throttlingRatio = std::min(_throttlingRatio, 1.0f); - qDebug("audio-mixer is struggling (%f mix/sleep) - throttling %f of streams", - (double)_trailingMixRatio, (double)_throttlingRatio); + qCDebug(audio) << "audio-mixer is struggling (" << _trailingMixRatio << "mix/sleep) - throttling" + << _throttlingRatio << "of streams"; } else if (_throttlingRatio > 0.0f && _trailingMixRatio <= BACKOFF_TARGET) { int proportionalTerm = 1 + (TARGET - _trailingMixRatio) / 0.2f; _throttlingRatio -= BACKOFF_RATE * proportionalTerm; _throttlingRatio = std::max(_throttlingRatio, 0.0f); - qDebug("audio-mixer is recovering (%f mix/sleep) - throttling %f of streams", - (double)_trailingMixRatio, (double)_throttlingRatio); + qCDebug(audio) << "audio-mixer is recovering (" << _trailingMixRatio << "mix/sleep) - throttling" + << _throttlingRatio << "of streams"; } } } @@ -534,7 +535,7 @@ void AudioMixer::clearDomainSettings() { } void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { - qDebug() << "AVX2 Support:" << (cpuSupportsAVX2() ? "enabled" : "disabled"); + qCDebug(audio) << "AVX2 Support:" << (cpuSupportsAVX2() ? "enabled" : "disabled"); if (settingsObject.contains(AUDIO_THREADING_GROUP_KEY)) { QJsonObject audioThreadingGroupObject = settingsObject[AUDIO_THREADING_GROUP_KEY].toObject(); @@ -557,7 +558,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { const QString DYNAMIC_JITTER_BUFFER_JSON_KEY = "dynamic_jitter_buffer"; bool enableDynamicJitterBuffer = audioBufferGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool(); if (enableDynamicJitterBuffer) { - qDebug() << "Enabling dynamic jitter buffers."; + qCDebug(audio) << "Enabling dynamic jitter buffers."; bool ok; const QString DESIRED_JITTER_BUFFER_FRAMES_KEY = "static_desired_jitter_buffer_frames"; @@ -565,9 +566,9 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { if (!ok) { _numStaticJitterFrames = InboundAudioStream::DEFAULT_STATIC_JITTER_FRAMES; } - qDebug() << "Static desired jitter buffer frames:" << _numStaticJitterFrames; + qCDebug(audio) << "Static desired jitter buffer frames:" << _numStaticJitterFrames; } else { - qDebug() << "Disabling dynamic jitter buffers."; + qCDebug(audio) << "Disabling dynamic jitter buffers."; _numStaticJitterFrames = DISABLE_STATIC_JITTER_FRAMES; } @@ -621,7 +622,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { if (audioEnvGroupObject[CODEC_PREFERENCE_ORDER].isString()) { QString codecPreferenceOrder = audioEnvGroupObject[CODEC_PREFERENCE_ORDER].toString(); _codecPreferenceOrder = codecPreferenceOrder.split(","); - qDebug() << "Codec preference order changed to" << _codecPreferenceOrder; + qCDebug(audio) << "Codec preference order changed to" << _codecPreferenceOrder; } const QString ATTENATION_PER_DOULING_IN_DISTANCE = "attenuation_per_doubling_in_distance"; @@ -630,7 +631,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { float attenuation = audioEnvGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].toString().toFloat(&ok); if (ok) { _attenuationPerDoublingInDistance = attenuation; - qDebug() << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance; + qCDebug(audio) << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance; } } @@ -640,7 +641,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { float noiseMutingThreshold = audioEnvGroupObject[NOISE_MUTING_THRESHOLD].toString().toFloat(&ok); if (ok) { _noiseMutingThreshold = noiseMutingThreshold; - qDebug() << "Noise muting threshold changed to" << _noiseMutingThreshold; + qCDebug(audio) << "Noise muting threshold changed to" << _noiseMutingThreshold; } } @@ -680,8 +681,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { glm::vec3 dimensions(xMax - xMin, yMax - yMin, zMax - zMin); AABox zoneAABox(corner, dimensions); _audioZones.insert(zone, zoneAABox); - qDebug() << "Added zone:" << zone << "(corner:" << corner - << ", dimensions:" << dimensions << ")"; + qCDebug(audio) << "Added zone:" << zone << "(corner:" << corner << ", dimensions:" << dimensions << ")"; } } } @@ -712,7 +712,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { _audioZones.contains(settings.source) && _audioZones.contains(settings.listener)) { _zoneSettings.push_back(settings); - qDebug() << "Added Coefficient:" << settings.source << settings.listener << settings.coefficient; + qCDebug(audio) << "Added Coefficient:" << settings.source << settings.listener << settings.coefficient; } } } @@ -745,7 +745,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { _zoneReverbSettings.push_back(settings); - qDebug() << "Added Reverb:" << zone << reverbTime << wetLevel; + qCDebug(audio) << "Added Reverb:" << zone << reverbTime << wetLevel; } } } diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 9bba9c7f30..49453c6fc6 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -19,6 +19,7 @@ #include "InjectedAudioStream.h" +#include "AudioLogging.h" #include "AudioHelpers.h" #include "AudioMixer.h" #include "AudioMixerClientData.h" @@ -132,7 +133,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c if (PacketTypeEnum::getReplicatedPacketMapping().key(message.getType()) != PacketType::Unknown) { mirroredType = message.getType(); } else { - qDebug() << "Packet passed to optionallyReplicatePacket was not a replicatable type - returning"; + qCDebug(audio) << "Packet passed to optionallyReplicatePacket was not a replicatable type - returning"; return; } } @@ -189,8 +190,16 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const uint8_t packedGain; message.readPrimitive(&packedGain); float gain = unpackFloatGainFromByte(packedGain); - hrtfForStream(avatarUuid, QUuid()).setGainAdjustment(gain); - qDebug() << "Setting gain adjustment for hrtf[" << uuid << "][" << avatarUuid << "] to " << gain; + + if (avatarUuid.isNull()) { + // set the MASTER avatar gain + setMasterAvatarGain(gain); + qCDebug(audio) << "Setting MASTER avatar gain for " << uuid << " to " << gain; + } else { + // set the per-source avatar gain + hrtfForStream(avatarUuid, QUuid()).setGainAdjustment(gain); + qCDebug(audio) << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUuid << "] to " << gain; + } } void AudioMixerClientData::parseNodeIgnoreRequest(QSharedPointer message, const SharedNodePointer& node) { @@ -276,7 +285,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { auto avatarAudioStream = new AvatarAudioStream(isStereo, AudioMixer::getStaticJitterFrames()); avatarAudioStream->setupCodec(_codec, _selectedCodecName, AudioConstants::MONO); - qDebug() << "creating new AvatarAudioStream... codec:" << _selectedCodecName; + qCDebug(audio) << "creating new AvatarAudioStream... codec:" << _selectedCodecName; connect(avatarAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioMixerClientData::handleMismatchAudioFormat); @@ -315,7 +324,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { #if INJECTORS_SUPPORT_CODECS injectorStream->setupCodec(_codec, _selectedCodecName, isStereo ? AudioConstants::STEREO : AudioConstants::MONO); - qDebug() << "creating new injectorStream... codec:" << _selectedCodecName; + qCDebug(audio) << "creating new injectorStream... codec:" << _selectedCodecName; #endif auto emplaced = _audioStreams.emplace( @@ -339,8 +348,8 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { auto parseResult = matchingStream->parseData(message); if (matchingStream->getOverflowCount() > overflowBefore) { - qDebug() << "Just overflowed on stream from" << message.getSourceID() << "at" << message.getSenderSockAddr(); - qDebug() << "This stream is for" << (isMicStream ? "microphone audio" : "injected audio"); + qCDebug(audio) << "Just overflowed on stream from" << message.getSourceID() << "at" << message.getSenderSockAddr(); + qCDebug(audio) << "This stream is for" << (isMicStream ? "microphone audio" : "injected audio"); } return parseResult; @@ -689,7 +698,7 @@ void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointerreadString(); if (codecString != _selectedCodecName) { - qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID()) + qCDebug(audio) << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID()) << "-" << codecString; const std::pair codec = AudioMixer::negotiateCodec({ codecString }); diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 7a8690d8cc..c3a31715ea 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -83,6 +83,9 @@ public: // uses randomization to have the AudioMixer send a stats packet to this node around every second bool shouldSendStats(int frameNumber); + float getMasterAvatarGain() const { return _masterAvatarGain; } + void setMasterAvatarGain(float gain) { _masterAvatarGain = gain; } + AudioLimiter audioLimiter; void setupCodec(CodecPluginPointer codec, const QString& codecName); @@ -175,6 +178,8 @@ private: int _frameToSendStats { 0 }; + float _masterAvatarGain { 1.0f }; // per-listener mixing gain, applied only to avatars + CodecPluginPointer _codec; QString _selectedCodecName; Encoder* _encoder{ nullptr }; // for outbound mixed stream diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index a131e266d2..6d150a0dc3 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -48,8 +48,8 @@ void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& // mix helpers inline float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); -inline float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, - const glm::vec3& relativePosition, bool isEcho); +inline float computeGain(const AudioMixerClientData& listenerNodeData, const AvatarAudioStream& listeningNodeStream, + const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, bool isEcho); inline float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); @@ -266,7 +266,7 @@ void AudioMixerSlave::addStream(AudioMixerClientData& listenerNodeData, const QU glm::vec3 relativePosition = streamToAdd.getPosition() - listeningNodeStream.getPosition(); float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = computeGain(listeningNodeStream, streamToAdd, relativePosition, isEcho); + float gain = computeGain(listenerNodeData, listeningNodeStream, streamToAdd, relativePosition, isEcho); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); const int HRTF_DATASET_INDEX = 1; @@ -484,10 +484,12 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi // when throttling, as close streams are expected to be heard by a user float distance = glm::length(relativePosition); return gain / distance; + + // avatar: skip master gain - it is constant for all streams } -float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, - const glm::vec3& relativePosition, bool isEcho) { +float computeGain(const AudioMixerClientData& listenerNodeData, const AvatarAudioStream& listeningNodeStream, + const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, bool isEcho) { float gain = 1.0f; // injector: apply attenuation @@ -507,6 +509,9 @@ float computeGain(const AvatarAudioStream& listeningNodeStream, const Positional float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + (angleOfDelivery * (OFF_AXIS_ATTENUATION_STEP / PI_OVER_TWO)); gain *= offAxisCoefficient; + + // apply master gain, only to avatars + gain *= listenerNodeData.getMasterAvatarGain(); } auto& audioZones = AudioMixer::getAudioZones(); diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index fa9c73b12d..995a5bad27 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -41,8 +41,15 @@ EntityServer::EntityServer(ReceivedMessage& message) : DependencyManager::set(); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, PacketType::EntityEdit, PacketType::EntityErase, PacketType::EntityPhysics, PacketType::ChallengeOwnership }, - this, "handleEntityPacket"); + packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, + PacketType::EntityEdit, + PacketType::EntityErase, + PacketType::EntityPhysics, + PacketType::ChallengeOwnership, + PacketType::ChallengeOwnershipRequest, + PacketType::ChallengeOwnershipReply }, + this, + "handleEntityPacket"); connect(&_dynamicDomainVerificationTimer, &QTimer::timeout, this, &EntityServer::startDynamicDomainVerification); _dynamicDomainVerificationTimer.setSingleShot(true); @@ -459,7 +466,7 @@ void EntityServer::startDynamicDomainVerification() { EntityItemPointer entity = tree->findEntityByEntityItemID(i.value()); if (entity) { - if (!entity->verifyStaticCertificateProperties()) { + if (!entity->getProperties().verifyStaticCertificateProperties()) { qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << i.value() << "failed" << "static certificate verification."; // Delete the entity if it doesn't pass static certificate verification diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 03014bae6a..e5cee84f1b 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -23,6 +23,17 @@ EntityTreeSendThread::EntityTreeSendThread(OctreeServer* myServer, const SharedN { connect(std::static_pointer_cast(myServer->getOctree()).get(), &EntityTree::editingEntityPointer, this, &EntityTreeSendThread::editingEntityPointer, Qt::QueuedConnection); connect(std::static_pointer_cast(myServer->getOctree()).get(), &EntityTree::deletingEntityPointer, this, &EntityTreeSendThread::deletingEntityPointer, Qt::QueuedConnection); + + // connect to connection ID change on EntityNodeData so we can clear state for this receiver + auto nodeData = static_cast(node->getLinkedData()); + connect(nodeData, &EntityNodeData::incomingConnectionIDChanged, this, &EntityTreeSendThread::resetState); +} + +void EntityTreeSendThread::resetState() { + qCDebug(entities) << "Clearing known EntityTreeSendThread state for" << _nodeUuid; + + _knownState.clear(); + _traversal.reset(); } void EntityTreeSendThread::preDistributionProcessing() { @@ -175,7 +186,7 @@ bool EntityTreeSendThread::addAncestorsToExtraFlaggedEntities(const QUuid& filte return parentWasNew || ancestorsWereNew; } - // since we didn't have a parent niether of our parents or ancestors could be new additions + // since we didn't have a parent, neither of our parents or ancestors could be new additions return false; } @@ -204,7 +215,9 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil return hasNewChild || hasNewDescendants; } -void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum) { +void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset, + bool usesViewFrustum) { + DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset, usesViewFrustum); // there are three types of traversal: // @@ -423,12 +436,19 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream uint64_t sendTime = usecTimestampNow(); auto nodeData = static_cast(params.nodeData); nodeData->stats.encodeStarted(); + auto entityNode = _node.toStrongRef(); + auto entityNodeData = static_cast(entityNode->getLinkedData()); while(!_sendQueue.empty()) { PrioritizedEntity queuedItem = _sendQueue.top(); EntityItemPointer entity = queuedItem.getEntity(); if (entity) { // Only send entities that match the jsonFilters, but keep track of everything we've tried to send so we don't try to send it again - if (entity->matchesJSONFilters(jsonFilters)) { + bool entityMatchesFilters = entity->matchesJSONFilters(jsonFilters); + if (entityMatchesFilters || entityNodeData->isEntityFlaggedAsExtra(entity->getID())) { + if (!jsonFilters.isEmpty() && entityMatchesFilters) { + // Record explicitly filtered-in entity so that extra entities can be flagged. + entityNodeData->insertSentFilteredEntity(entity->getID()); + } OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData); if (appendEntityState != OctreeElement::COMPLETED) { diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h index 49901491ff..594f423838 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.h +++ b/assignment-client/src/entities/EntityTreeSendThread.h @@ -33,12 +33,16 @@ protected: void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) override; +private slots: + void resetState(); // clears our known state forcing entities to appear unsent + private: // the following two methods return booleans to indicate if any extra flagged entities were new additions to set bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); - void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum); + void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, + bool usesViewFrustum); bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override; void preDistributionProcessing() override; diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 3f835678ac..bce6e7fe44 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -96,6 +96,14 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer _myServer->getOctree()->withWriteLock([&] { _myServer->getOctree()->processChallengeOwnershipPacket(*message, sendingNode); }); + } else if (packetType == PacketType::ChallengeOwnershipRequest) { + _myServer->getOctree()->withWriteLock([&] { + _myServer->getOctree()->processChallengeOwnershipRequestPacket(*message, sendingNode); + }); + } else if (packetType == PacketType::ChallengeOwnershipReply) { + _myServer->getOctree()->withWriteLock([&] { + _myServer->getOctree()->processChallengeOwnershipReplyPacket(*message, sendingNode); + }); } else if (_myServer->getOctree()->handlesEditPacketType(packetType)) { PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket); _receivedPacketCount++; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 89e3d403fc..3ae653307f 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -82,8 +82,12 @@ bool OctreeSendThread::process() { if (auto node = _node.lock()) { OctreeQueryNode* nodeData = static_cast(node->getLinkedData()); - // Sometimes the node data has not yet been linked, in which case we can't really do anything - if (nodeData && !nodeData->isShuttingDown()) { + // If we don't have the OctreeQueryNode at all + // or it's uninitialized because we haven't received a query yet from the client + // or we don't know where we should send packets for this node + // or we're shutting down + // then we can't send an entity data packet + if (nodeData && nodeData->hasReceivedFirstQuery() && node->getActiveSocket() && !nodeData->isShuttingDown()) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); packetDistributor(node, nodeData, viewFrustumChanged); } diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index bc7d2c2588..220952e209 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -59,7 +59,8 @@ protected: OctreePacketData _packetData; QWeakPointer _node; OctreeServer* _myServer { nullptr }; - + QUuid _nodeUuid; + private: /// Called before a packetDistributor pass to allow for pre-distribution processing virtual void preDistributionProcessing() {}; @@ -71,8 +72,6 @@ private: virtual void preStartNewScene(OctreeQueryNode* nodeData, bool isFullScene); virtual bool shouldTraverseAndSend(OctreeQueryNode* nodeData) { return hasSomethingToSend(nodeData); } - QUuid _nodeUuid; - int _truePacketsSent { 0 }; // available for debug stats int _trueBytesSent { 0 }; // available for debug stats int _packetsSentThisInterval { 0 }; // used for bandwidth throttle condition diff --git a/cmake/externals/hifiAudioCodec/CMakeLists.txt b/cmake/externals/hifiAudioCodec/CMakeLists.txt index a30396c6fd..e3ba36a440 100644 --- a/cmake/externals/hifiAudioCodec/CMakeLists.txt +++ b/cmake/externals/hifiAudioCodec/CMakeLists.txt @@ -5,43 +5,41 @@ set(EXTERNAL_NAME hifiAudioCodec) string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) -if (NOT ANDROID) - - if (WIN32 OR APPLE) - ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip - URL_MD5 23ec3fe51eaa155ea159a4971856fc13 - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - LOG_DOWNLOAD 1 - ) - else () - ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip - URL_MD5 7d37914a18aa4de971d2f45dd3043bde - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - LOG_DOWNLOAD 1 - ) - endif() - - # Hide this external target (for ide users) - set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") - - ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) - - set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL) - - if (WIN32) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL) - elseif(APPLE) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL) - elseif(NOT ANDROID) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL) - endif() - +if (WIN32) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-win-2.0.zip) + set(DOWNLOAD_MD5 9199d4dbd6b16bed736b235efe980e67) +elseif (APPLE) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-mac-2.0.zip) + set(DOWNLOAD_MD5 21649881e7d5dc94f922179be96f76ba) +elseif (ANDROID) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-android-2.0.zip) + set(DOWNLOAD_MD5 aef2a852600d498d58aa586668191683) +elseif (UNIX) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux-2.0.zip) + set(DOWNLOAD_MD5 67fb7755f9bcafb98a9fceea53bc7481) +else() + return() +endif() + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL ${DOWNLOAD_URL} + URL_MD5 ${DOWNLOAD_MD5} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL) + +if (WIN32) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL) +else() + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL) endif() diff --git a/cmake/externals/wasapi/CMakeLists.txt b/cmake/externals/wasapi/CMakeLists.txt index 4437024962..4c0ffaf88f 100644 --- a/cmake/externals/wasapi/CMakeLists.txt +++ b/cmake/externals/wasapi/CMakeLists.txt @@ -6,8 +6,8 @@ if (WIN32) include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi9.zip - URL_MD5 94f4765bdbcd53cd099f349ae031e769 + URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi10.zip + URL_MD5 4f40e49715a420fb67b45b9cee19052c CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 338dee7bc8..0619c4d587 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -60,7 +60,7 @@ if (WIN32 AND NOT CYGWIN) select_library_configurations(LIB_EAY) select_library_configurations(SSL_EAY) set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY}) - find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS}) + find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} NO_DEFAULT_PATH) endif() else() diff --git a/domain-server/resources/web/content/index.shtml b/domain-server/resources/web/content/index.shtml index e1ba5499b6..0e48c1eff8 100644 --- a/domain-server/resources/web/content/index.shtml +++ b/domain-server/resources/web/content/index.shtml @@ -19,12 +19,13 @@ Upload an entities file (e.g.: models.json.gz) to replace the content of this domain.
Note: Your domain's content will be replaced by the content you upload, but the backup files of your domain's content will not immediately be changed.

-

- If your domain has any content that you would like to re-use at a later date, save a manual backup of your models.json.gz file, which is usually stored at the following paths:
-

C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz
-
/Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz
-
/home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz
-

+

If your domain has any content that you would like to re-use at a later date, save a manual backup of your models.json.gz file, which is usually stored at the following paths:

+ +
C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz
+ +
/Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz
+ +
/home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz


diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index 8b004687b9..f5a618e2c1 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -80,11 +80,23 @@ span.port { display: none; } -#setup-sidebar.affix { - /* This overrides a case where going to the bottom of the page, - * then scrolling up, causes `position: relative` to be added to the style - */ - position: fixed !important; +@media (min-width: 768px) { + #setup-sidebar.affix { + /* This overrides a case where going to the bottom of the page, + * then scrolling up, causes `position: relative` to be added to the style + */ + position: fixed !important; + } +} + +@media (max-width: 767px) { + #setup-sidebar.affix { + position: static !important; + } + + #setup-sidebar { + margin-bottom: 20px; + } } #setup-sidebar button { @@ -302,12 +314,12 @@ table .headers + .headers td { } .account-connected-header { + vertical-align: middle; color: #6FCF97; font-size: 30px; margin-right: 20px; } -#visit-domain-link, .blue-link { font-size: 14px; text-decoration-line: underline; diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index 7b07458784..1e32e9f02f 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -39,7 +39,7 @@
  • Settings
  • diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index a5dd522a53..00f699fa4e 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -62,26 +62,25 @@ var Strings = { // dialog with new path still set, allowing them to retry immediately, and without // having to type the new path in again. EDIT_PLACE_TITLE: "Modify Viewpoint or Path", - EDIT_PLACE_ERROR: "Failed to update place path. Please try again.", + EDIT_PLACE_ERROR: "Failed to update Viewpoint or Path for this Place Name. Please try again.", EDIT_PLACE_CONFIRM_BUTTON: "Save", EDIT_PLACE_CONFIRM_BUTTON_PENDING: "Saving...", EDIT_PLACE_CANCEL_BUTTON: "Cancel", - REMOVE_PLACE_TITLE: "Are you sure you want to remove {{place}}?", - REMOVE_PLACE_ERROR: "Failed to remove place. Please try again.", - REMOVE_PLACE_DELETE_BUTTON: "Delete", + REMOVE_PLACE_TITLE: "Are you sure you want to remove {{place}} and its path information?", + REMOVE_PLACE_ERROR: "Failed to remove Place Name and its Path information.", + REMOVE_PLACE_DELETE_BUTTON: "This action removes your Place Name", REMOVE_PLACE_DELETE_BUTTON_PENDING: "Deleting...", REMOVE_PLACE_CANCEL_BUTTON: "Cancel", ADD_PLACE_TITLE: "Choose a place", - ADD_PLACE_MESSAGE: "Choose the High Fidelity place to point at this domain server.", - ADD_PLACE_CONFIRM_BUTTON: "Choose place", + ADD_PLACE_MESSAGE: "Choose a Place Name that you own or register a new Place Name.", + ADD_PLACE_CONFIRM_BUTTON: "Save", ADD_PLACE_CONFIRM_BUTTON_PENDING: "Saving...", ADD_PLACE_CANCEL_BUTTON: "Cancel", - ADD_PLACE_UNKNOWN_ERROR: "There was an error adding this place name.", + ADD_PLACE_UNKNOWN_ERROR: "There was an error adding this Place Name. Try saving again", - ADD_PLACE_NO_PLACES_MESSAGE: "

    You do not have any places in your High Fidelity account." - + "

    Go to your places page to create a new one. Once your place is created re-open this dialog to select it.

    ", + ADD_PLACE_NO_PLACES_MESSAGE: "You don't have any Place Names registered. Once you have a Place Name, reopen this window to select it.", ADD_PLACE_NO_PLACES_BUTTON: "Create new place", ADD_PLACE_UNABLE_TO_LOAD_ERROR: "We were unable to load your place names. Please try again later.", ADD_PLACE_LOADING_DIALOG: "Loading your places...", @@ -146,187 +145,256 @@ function sendUpdatePlaceRequest(id, path, domainID, clearDomainID, onSuccess, on }); } +var pendingDomainRequest = null; +function getDomainFromAPI(callback) { + if (pendingDomainRequest !== null) { + pendingDomainRequest.success(callback); + pendingDomainRequest.error(function() { callback({ status: 'fail' }) }); + return pendingDomainRequest; + } + + if (callback === undefined) { + callback = function() {}; + } + + var domainID = Settings.data.values.metaverse.id; + if (domainID === null || domainID === undefined || domainID === '') { + callback({ status: 'fail' }); + return null; + } + + pendingDomainRequest = $.ajax({ + url: "/api/domains/" + domainID, + dataType: 'json', + success: function(data) { + pendingDomainRequest = null; + + if (data.status === 'success') { + DomainInfo = data.domain; + } else { + DomainInfo = null; + } + callback(data); + }, + error: function() { + pendingDomainRequest = null; + + DomainInfo = null; + callback({ status: 'fail' }); + } + }); + + return pendingDomainRequest; +} + function chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAdded) { if (accessToken) { var loadingDialog = showLoadingDialog(Strings.ADD_PLACE_LOADING_DIALOG); - $.ajax("/api/places", { - dataType: 'json', - jsonp: false, - success: function(data) { - if (data.status == 'success') { - var modal_buttons = { - cancel: { - label: Strings.ADD_PLACE_CANCEL_BUTTON, - className: 'add-place-cancel-button btn-default' - } - }; - - var dialog; - var modal_body; - - if (data.data.places.length) { - var places_by_id = {}; - - modal_body = $('
    '); - - modal_body.append($("

    Choose a place name that you own or register a new place name

    ")); - - var currentDomainIDType = getCurrentDomainIDType(); - if (currentDomainIDType === DOMAIN_ID_TYPE_TEMP) { - var warning = "
    "; - warning += "If you choose a place name it will replace your current temporary place name."; - warning += "
    "; - modal_body.append(warning); - } - - // setup a select box for the returned places - modal_body.append($("")); - place_select = $(""); - _.each(data.data.places, function(place) { - places_by_id[place.id] = place; - place_select.append(""); - }) - modal_body.append(place_select); - modal_body.append($("")); - - if (forcePathTo === undefined || forcePathTo === null) { - var path = "
    "; - path += ""; - path += ""; - path += "
    "; - modal_body.append($(path)); - } - - var place_select = modal_body.find("#place-name-select") - place_select.change(function(ev) { - var warning = modal_body.find("#place-name-warning"); - var place = places_by_id[$(this).val()]; - if (place === undefined || place.pointee === null) { - warning.hide(); - } else { - warning.show(); + function loadPlaces() { + $.ajax("/api/places", { + dataType: 'json', + jsonp: false, + success: function(data) { + if (data.status == 'success') { + var modal_buttons = { + cancel: { + label: Strings.ADD_PLACE_CANCEL_BUTTON, + className: 'add-place-cancel-button btn-default' } - }); - place_select.trigger('change'); + }; - modal_buttons["success"] = { - label: Strings.ADD_PLACE_CONFIRM_BUTTON, - className: 'add-place-confirm-button btn btn-primary', - callback: function() { - var placeID = $('#place-name-select').val(); - // set the place ID on the form - $(Settings.place_ID_SELECTOR).val(placeID).change(); + var dialog; + var modal_body; - if (forcePathTo === undefined || forcePathTo === null) { - var placePath = $('#place-path-input').val(); + if (data.data.places.length) { + var places_by_id = {}; + + modal_body = $('
    '); + + modal_body.append($("

    Choose a place name that you own or register a new place name

    ")); + + var currentDomainIDType = getCurrentDomainIDType(); + if (currentDomainIDType === DOMAIN_ID_TYPE_TEMP) { + var warning = "
    "; + warning += "If you choose a place name it will replace your current temporary place name."; + warning += "
    "; + modal_body.append(warning); + } + + // setup a select box for the returned places + modal_body.append($("")); + place_select = $(""); + _.each(data.data.places, function(place) { + places_by_id[place.id] = place; + place_select.append(""); + }) + modal_body.append(place_select); + modal_body.append($("")); + + if (forcePathTo === undefined || forcePathTo === null) { + var path = "
    "; + path += ""; + path += ""; + path += "
    "; + modal_body.append($(path)); + } + + var place_select = modal_body.find("#place-name-select") + place_select.change(function(ev) { + var warning = modal_body.find("#place-name-warning"); + var place = places_by_id[$(this).val()]; + if (place === undefined || place.pointee === null) { + warning.hide(); } else { - var placePath = forcePathTo; + warning.show(); } + }); + place_select.trigger('change'); - $('.add-place-confirm-button').attr('disabled', 'disabled'); - $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON_PENDING); - $('.add-place-cancel-button').attr('disabled', 'disabled'); + modal_buttons["success"] = { + label: Strings.ADD_PLACE_CONFIRM_BUTTON, + className: 'add-place-confirm-button btn btn-primary', + callback: function() { + var placeID = $('#place-name-select').val(); + // set the place ID on the form + $(Settings.place_ID_SELECTOR).val(placeID).change(); - function finalizeSaveDomainID(domainID) { - var jsonSettings = { - metaverse: { - id: domainID + if (forcePathTo === undefined || forcePathTo === null) { + var placePath = $('#place-path-input').val(); + } else { + var placePath = forcePathTo; + } + + $('.add-place-confirm-button').attr('disabled', 'disabled'); + $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON_PENDING); + $('.add-place-cancel-button').attr('disabled', 'disabled'); + + function finalizeSaveDomainID(domainID) { + var jsonSettings = { + metaverse: { + id: domainID + } + } + var dialog = showLoadingDialog("Waiting for Domain Server to restart..."); + $.ajax('/settings.json', { + data: JSON.stringify(jsonSettings), + contentType: 'application/json', + type: 'POST' + }).done(function(data) { + if (data.status == "success") { + waitForDomainServerRestart(function() { + dialog.modal('hide'); + if (onSuccessfullyAdded) { + onSuccessfullyAdded(places_by_id[placeID].name, domainID); + } + }); + } else { + bootbox.alert("Failed to add place"); + } + }).fail(function() { + bootbox.alert("Failed to add place"); + }); + } + + // If domainID is not specified, the current domain id will be used. + function finishSettingUpPlace(domainID) { + sendUpdatePlaceRequest( + placeID, + placePath, + domainID, + false, + function(data) { + dialog.modal('hide') + if (domainID) { + $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); + finalizeSaveDomainID(domainID); + } else { + if (onSuccessfullyAdded) { + onSuccessfullyAdded(places_by_id[placeID].name); + } + } + }, + function(data) { + $('.add-place-confirm-button').removeAttr('disabled'); + $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON); + $('.add-place-cancel-button').removeAttr('disabled'); + bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR); + } + ); + } + + function maybeCreateNewDomainID() { + console.log("Maybe creating domain id", currentDomainIDType) + if (currentDomainIDType === DOMAIN_ID_TYPE_FULL) { + finishSettingUpPlace(); + } else { + sendCreateDomainRequest(function(domainID) { + console.log("Created domain", domainID); + finishSettingUpPlace(domainID); + }, function() { + $('.add-place-confirm-button').removeAttr('disabled'); + $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON); + $('.add-place-cancel-button').removeAttr('disabled'); + bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR); + }); } } - var dialog = showLoadingDialog("Waiting for Domain Server to restart..."); - $.ajax('/settings.json', { - data: JSON.stringify(jsonSettings), - contentType: 'application/json', - type: 'POST' - }).done(function(data) { - if (data.status == "success") { - waitForDomainServerRestart(function() { - dialog.modal('hide'); - if (onSuccessfullyAdded) { - onSuccessfullyAdded(places_by_id[placeID].name, domainID); - } - }); - } else { - bootbox.alert("Failed to add place"); - } - }).fail(function() { - bootbox.alert("Failed to add place"); - }); - } - function finishSettingUpPlace(domainID) { - sendUpdatePlaceRequest( - placeID, - placePath, - domainID, - false, - function(data) { - $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); - dialog.modal('hide') - if (domainID) { - finalizeSaveDomainID(domainID); - } else { - if (onSuccessfullyAdded) { - onSuccessfullyAdded(places_by_id[placeID].name); - } - } - }, - function(data) { - $('.add-place-confirm-button').removeAttr('disabled'); - $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON); - $('.add-place-cancel-button').removeAttr('disabled'); - bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR); - } - ); - } + maybeCreateNewDomainID(); - if (currentDomainIDType === DOMAIN_ID_TYPE_FULL) { - finishSettingUpPlace(); - } else { - sendCreateDomainRequest(function(domainID) { - console.log("Created domain", domainID); - finishSettingUpPlace(domainID); - }, function() { - $('.add-place-confirm-button').removeAttr('disabled'); - $('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON); - $('.add-place-cancel-button').removeAttr('disabled'); - bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR); - bootbox.alert("FAIL"); - }); + return false; } - - return false; } + } else { + modal_buttons["success"] = { + label: Strings.ADD_PLACE_NO_PLACES_BUTTON, + callback: function() { + window.open(URLs.METAVERSE_URL + "/user/places", '_blank'); + } + } + modal_body = Strings.ADD_PLACE_NO_PLACES_MESSAGE; } + + dialog = bootbox.dialog({ + title: Strings.ADD_PLACE_TITLE, + message: modal_body, + closeButton: false, + buttons: modal_buttons, + onEscape: true + }); } else { - modal_buttons["success"] = { - label: Strings.ADD_PLACE_NO_PLACES_BUTTON, - callback: function() { - window.open(URLs.METAVERSE_URL + "/user/places", '_blank'); - } - } - modal_body = Strings.ADD_PLACE_NO_PLACES_MESSAGE; + bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR); } - - dialog = bootbox.dialog({ - title: Strings.ADD_PLACE_TITLE, - message: modal_body, - closeButton: false, - buttons: modal_buttons - }); - } else { + }, + error: function() { bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR); + }, + complete: function() { + loadingDialog.modal('hide'); } - }, - error: function() { - bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR); - }, - complete: function() { - loadingDialog.modal('hide'); - } - }); + }); + } + + var domainType = getCurrentDomainIDType(); + if (domainType !== DOMAIN_ID_TYPE_UNKNOWN) { + loadPlaces(); + } else { + getDomainFromAPI(function(data) { + if (data.status === 'success') { + var domainType = getCurrentDomainIDType(); + loadPlaces(); + } else { + loadingDialog.modal('hide'); + bootbox.confirm("We were not able to load your domain information from the Metaverse. Would you like to retry?", function(response) { + if (response) { + chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAdded); + } + }); + } + }) + } } else { bootbox.alert({ diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index 5a8184db30..d36330375a 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -36,11 +36,6 @@
    - - -