From 7b179ab91aac3ec14b26cb17ccf7b46f348985fc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 29 Feb 2016 16:57:24 -0800 Subject: [PATCH 001/258] First draft for mapping requests --- assignment-client/src/assets/AssetServer.cpp | 27 +++++++ assignment-client/src/assets/AssetServer.h | 7 ++ libraries/networking/src/AssetClient.cpp | 79 ++++++++++++++++++- libraries/networking/src/AssetClient.h | 6 +- libraries/networking/src/AssetRequest.cpp | 5 +- libraries/networking/src/AssetRequest.h | 7 +- .../networking/src/AssetResourceRequest.cpp | 14 +--- libraries/networking/src/udt/PacketHeaders.h | 4 +- 8 files changed, 128 insertions(+), 21 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4ca2439996..ab86787769 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -39,6 +39,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : _taskPool.setMaxThreadCount(TASK_POOL_THREAD_COUNT); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AssetGetMapping, this, "handleAssetGetMapping"); packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); @@ -161,6 +162,32 @@ void AssetServer::completeSetup() { nodeList->addNodeTypeToInterestSet(NodeType::Agent); } + +void AssetServer::handleAssetGetMapping(QSharedPointer packet, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + QString assetPath = message->readAll(); + + auto replyPacket = NLPacket::create(PacketType::AssetGetMappingReply); + + replyPacket->writePrimitive(messageID); + + auto it = _fileMapping.find(assetPath.toStdString()); + + if (it != _fileMapping.end()) { + auto assetHash = QString::fromStdString(it.second); + qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(assetHash.toHex()); + } else { + qDebug() << "Mapping not found for: " << assetPath; + replyPacket->writePrimitive(AssetServerError::AssetNotFound); + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(replyPacket), *senderNode); +} + void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 7d6e26af08..90e1eb8f34 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -31,6 +31,7 @@ public slots: private slots: void completeSetup(); + void handleAssetGetMapping(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); @@ -39,6 +40,12 @@ private slots: private: static void writeError(NLPacketList* packetList, AssetServerError error); + + using Path = std::string; + using Hash = std::string; + using Mapping = std::map; + + Mapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 9591828fef..a61e30a8c1 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -39,6 +39,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AssetGetMappingReply, this, "handleAssetGetMappingReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); @@ -110,7 +111,22 @@ bool haveAssetServer() { return true; } -AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) { +AssetRequest* AssetClient::createRequest(const QUrl& url) { + + auto parts = _url.path().split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + auto extension = parts.length() > 1 ? parts[1] : ""; + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; + + emit finished(); + return; + } + + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; return nullptr; @@ -155,6 +171,34 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } +bool AssetClient::getAssetMapping(const QString& path, GetMappingCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto messageID = ++_currentID; + + auto payload = path.toLatin1(); + auto payloadSize = sizeof(messageID) + payload.size(); + auto packet = NLPacket::create(PacketType::AssetGetMapping, payloadSize, true); + + qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; + + packet->writePrimitive(messageID); + + auto bytesWritten = packet->write(payload); + Q_ASSERT(bytesWritten == payload.size()); + + nodeList->sendPacket(std::move(packet), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { @@ -220,6 +264,39 @@ bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, Ge return false; } + +void AssetClient::handleAssetGetMappingReply(QSharedPointer message, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + + AssetServerError error; + message->readPrimitive(&error); + + QString assetHash; + if (error == AssetServerError::NoError) { + assetHash = message->read(SHA256_HASH_LENGTH); + } + + // Check if we have any pending requests for this node + auto messageMapIt = _pendingMappingRequests.find(senderNode); + if (messageMapIt != _pendingMappingRequests.end()) { + + // Found the node, get the MessageID -> Callback map + auto& messageCallbackMap = messageMapIt->second; + + // Check if we have this pending request + auto requestIt = messageCallbackMap.find(messageID); + if (requestIt != messageCallbackMap.end()) { + auto callback = requestIt->second; + callback(true, error, assetHash); + messageCallbackMap.erase(requestIt); + } + + // Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from + // it to avoid constantly creating/deleting the map on subsequent requests. + } +} + void AssetClient::handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; message->readPrimitive(&messageID); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f66fe8adcc..cbbf603de6 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -34,6 +34,7 @@ struct AssetInfo { }; using ReceivedAssetCallback = std::function; +using GetMappingCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; @@ -44,7 +45,7 @@ class AssetClient : public QObject, public Dependency { public: AssetClient(); - Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension); + Q_INVOKABLE AssetRequest* createRequest(const QUrl& url); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); @@ -55,6 +56,7 @@ public slots: void clearCache(); private slots: + void handleAssetGetMappingReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode); @@ -62,6 +64,7 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: + bool getAssetMapping(const QString& path, GetMappingCallback callback); bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); @@ -73,6 +76,7 @@ private: }; static MessageID _currentID; + std::unordered_map> _pendingMappingRequests; std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 19f91349fb..505b64e080 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -20,9 +20,8 @@ #include "NodeList.h" #include "ResourceCache.h" -AssetRequest::AssetRequest(const QString& hash, const QString& extension) : - QObject(), - _hash(hash), +AssetRequest::AssetRequest(const QString& url, const QString& extension) : + _url(url), _extension(extension) { } diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 3c3459b15d..288caac6df 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -39,7 +39,7 @@ public: UnknownError }; - AssetRequest(const QString& hash, const QString& extension); + AssetRequest(const QString& url, const QString& extension); Q_INVOKABLE void start(); @@ -52,12 +52,15 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); +private slots: + void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); + private: State _state = NotStarted; Error _error = NoError; AssetInfo _info; uint64_t _totalReceived { 0 }; - QString _hash; + QString _url; QString _extension; QByteArray _data; int _numPendingRequests { 0 }; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index dac3329153..0025ba565a 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -23,19 +23,7 @@ AssetResourceRequest::~AssetResourceRequest() { void AssetResourceRequest::doSend() { // Make request to atp auto assetClient = DependencyManager::get(); - auto parts = _url.path().split(".", QString::SkipEmptyParts); - auto hash = parts.length() > 0 ? parts[0] : ""; - auto extension = parts.length() > 1 ? parts[1] : ""; - - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; - - emit finished(); - return; - } - - _assetRequest = assetClient->createRequest(hash, extension); + _assetRequest = assetClient->createRequest(_url); if (!_assetRequest) { _result = ServerUnavailable; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0f586018db..3d92aa1285 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -90,7 +90,9 @@ public: DomainServerRemovedNode, MessagesData, MessagesSubscribe, - MessagesUnsubscribe + MessagesUnsubscribe, + AssetGetMapping, + AssetGetMappingReply }; }; From db98e46bb8f3379bff5d938d4b15592c00fcec7b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Mar 2016 16:18:35 -0800 Subject: [PATCH 002/258] Update atp mapping operations to use a single packet --- assignment-client/src/assets/AssetServer.cpp | 58 +++++++++++++++----- assignment-client/src/assets/AssetServer.h | 19 +++++-- libraries/networking/src/AssetClient.cpp | 2 +- libraries/networking/src/AssetClient.h | 6 +- libraries/networking/src/AssetUtils.h | 6 ++ libraries/networking/src/ReceivedMessage.cpp | 9 +++ libraries/networking/src/ReceivedMessage.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 4 +- 8 files changed, 82 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ab86787769..50723c77c0 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -39,10 +39,10 @@ AssetServer::AssetServer(ReceivedMessage& message) : _taskPool.setMaxThreadCount(TASK_POOL_THREAD_COUNT); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetGetMapping, this, "handleAssetGetMapping"); packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); + packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOpertation"); } void AssetServer::run() { @@ -163,25 +163,45 @@ void AssetServer::completeSetup() { } -void AssetServer::handleAssetGetMapping(QSharedPointer packet, SharedNodePointer senderNode) { +void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; message->readPrimitive(&messageID); - QString assetPath = message->readAll(); - auto replyPacket = NLPacket::create(PacketType::AssetGetMappingReply); + AssetMappingOperationType operationType; + message->readPrimitive(&operationType); + auto replyPacket = NLPacket::create(PacketType::AssetMappingOperationReply); replyPacket->writePrimitive(messageID); - auto it = _fileMapping.find(assetPath.toStdString()); + switch (operationType) { + case AssetMappingOperationType::Get: { + QString assetPath = message->readString(); - if (it != _fileMapping.end()) { - auto assetHash = QString::fromStdString(it.second); - qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(assetHash.toHex()); - } else { - qDebug() << "Mapping not found for: " << assetPath; - replyPacket->writePrimitive(AssetServerError::AssetNotFound); + auto it = _fileMapping.find(assetPath); + if (it != _fileMapping.end()) { + auto assetHash = it->second; + qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(assetHash.toLatin1().toHex()); + } + else { + qDebug() << "Mapping not found for: " << assetPath; + replyPacket->writePrimitive(AssetServerError::AssetNotFound); + } + } + case AssetMappingOperationType::Set: { + QString assetPath = message->readString(); + auto assetHash = message->read(SHA256_HASH_LENGTH); + _fileMapping[assetPath] = assetHash; + + replyPacket->writePrimitive(AssetServerError::NoError); + } + case AssetMappingOperationType::Delete: { + QString assetPath = message->readString(); + bool removed = _fileMapping.erase(assetPath) > 0; + + replyPacket->writePrimitive(AssetServerError::NoError); + } } auto nodeList = DependencyManager::get(); @@ -335,3 +355,15 @@ void AssetServer::sendStatsPacket() { // send off the stats packets ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } + +AssetServer::Hash AssetServer::getMapping(Path path) { + return _fileMapping[path]; +} + +void AssetServer::setMapping(Path path, Hash hash) { + _fileMapping[path] = hash; +} + +bool AssetServer::deleteMapping(Path path) { + return _fileMapping.erase(path) > 0; +} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 90e1eb8f34..5287c222aa 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -31,19 +31,28 @@ public slots: private slots: void completeSetup(); - void handleAssetGetMapping(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); + void handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode); void sendStatsPacket(); private: - static void writeError(NLPacketList* packetList, AssetServerError error); + using Path = QString; + using Hash = QString; + using Mapping = std::unordered_map; - using Path = std::string; - using Hash = std::string; - using Mapping = std::map; + /// Return the hash mapping for Path `path` + Hash getMapping(Path path); + + /// Set the mapping for path to hash + void setMapping(Path path, Hash hash); + + /// Delete mapping `path`. Return `true` if mapping existed, else `false`. + bool deleteMapping(Path path); + + static void writeError(NLPacketList* packetList, AssetServerError error); Mapping _fileMapping; QDir _resourcesDirectory; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index a61e30a8c1..22671b729d 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -39,7 +39,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetGetMappingReply, this, "handleAssetGetMappingReply"); + packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index cbbf603de6..1b74a47f99 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -34,7 +34,7 @@ struct AssetInfo { }; using ReceivedAssetCallback = std::function; -using GetMappingCallback = std::function; +using MappingOperationCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; @@ -64,7 +64,7 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: - bool getAssetMapping(const QString& path, GetMappingCallback callback); + bool getAssetMapping(const QString& path, MappingOperationCallback callback); bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); @@ -76,7 +76,7 @@ private: }; static MessageID _currentID; - std::unordered_map> _pendingMappingRequests; + std::unordered_map> _pendingMappingRequests; std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 21b6b3f434..58e7aa6146 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -32,6 +32,12 @@ enum AssetServerError : uint8_t { PermissionDenied }; +enum AssetMappingOperationType : uint8_t { + Get = 0, + Set, + Delete +}; + QUrl getATPUrl(const QString& hash, const QString& extension = QString()); QByteArray hashData(const QByteArray& data); diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index 651b856923..eed275dc1a 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -107,6 +107,15 @@ QByteArray ReceivedMessage::readAll() { return read(getBytesLeftToRead()); } +QString ReceivedMessage::readString() { + uint32_t size; + readPrimitive(&size); + Q_ASSERT(size <= _size - _position); + auto string = QString::fromUtf8(_data.constData(), size); + _position += size; + return string; +} + QByteArray ReceivedMessage::readWithoutCopy(qint64 size) { QByteArray data { QByteArray::fromRawData(_data.constData() + _position, size) }; _position += size; diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index 1f797f1262..b813149bed 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -63,6 +63,8 @@ public: QByteArray read(qint64 size); QByteArray readAll(); + QString readString(); + QByteArray readHead(qint64 size); // This will return a QByteArray referencing the underlying data _without_ refcounting that data. diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3d92aa1285..c830978e92 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -91,8 +91,8 @@ public: MessagesData, MessagesSubscribe, MessagesUnsubscribe, - AssetGetMapping, - AssetGetMappingReply + AssetMappingOperation, + AssetMappingOperationReply }; }; From 9148db2612a4b801ba2579b93a03af89bbc4515d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:22:23 -0800 Subject: [PATCH 003/258] Clean up AssetServer mapping handling --- assignment-client/src/assets/AssetServer.cpp | 23 +++++++++++++++----- assignment-client/src/assets/AssetServer.h | 15 +++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 50723c77c0..f685bbe1a9 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -42,7 +42,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); - packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOpertation"); + packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation"); } void AssetServer::run() { @@ -182,25 +182,30 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me auto assetHash = it->second; qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(assetHash.toLatin1().toHex()); + //replyPacket->write(assetHash.toLatin1().toHex()); + replyPacket->writeString(assetHash.toLatin1()); } else { qDebug() << "Mapping not found for: " << assetPath; replyPacket->writePrimitive(AssetServerError::AssetNotFound); } + break; } case AssetMappingOperationType::Set: { QString assetPath = message->readString(); - auto assetHash = message->read(SHA256_HASH_LENGTH); + //auto assetHash = message->read(SHA256_HASH_LENGTH); + auto assetHash = message->readString(); _fileMapping[assetPath] = assetHash; replyPacket->writePrimitive(AssetServerError::NoError); + break; } case AssetMappingOperationType::Delete: { QString assetPath = message->readString(); bool removed = _fileMapping.erase(assetPath) > 0; replyPacket->writePrimitive(AssetServerError::NoError); + break; } } @@ -356,14 +361,20 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } -AssetServer::Hash AssetServer::getMapping(Path path) { +void AssetServer::loadMappingFromFile() { +} + +void AssetServer::writeMappingToFile() { +} + +AssetHash AssetServer::getMapping(AssetPath path) { return _fileMapping[path]; } -void AssetServer::setMapping(Path path, Hash hash) { +void AssetServer::setMapping(AssetPath path, AssetHash hash) { _fileMapping[path] = hash; } -bool AssetServer::deleteMapping(Path path) { +bool AssetServer::deleteMapping(AssetPath path) { return _fileMapping.erase(path) > 0; } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 5287c222aa..1eee4feb94 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,18 +39,19 @@ private slots: void sendStatsPacket(); private: - using Path = QString; - using Hash = QString; - using Mapping = std::unordered_map; + using Mapping = std::map; - /// Return the hash mapping for Path `path` - Hash getMapping(Path path); + void loadMappingFromFile(); + void writeMappingToFile(); + + /// Return the hash mapping for AssetPath `path` + AssetHash getMapping(AssetPath path); /// Set the mapping for path to hash - void setMapping(Path path, Hash hash); + void setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Return `true` if mapping existed, else `false`. - bool deleteMapping(Path path); + bool deleteMapping(AssetPath path); static void writeError(NLPacketList* packetList, AssetServerError error); From 4e7b63c72e363579a6ebc6bc568fc317f7bd74d6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:00 -0800 Subject: [PATCH 004/258] Add get/set mapping request --- libraries/networking/src/AssetClient.cpp | 227 +++++++++++++++-------- 1 file changed, 149 insertions(+), 78 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 22671b729d..f3d677a98a 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -30,6 +30,43 @@ MessageID AssetClient::_currentID = 0; +GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { +}; + +void GetMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->getAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + if (!error) { + //_hash = message->read(SHA256_HASH_HEX_LENGTH); + _hash = message->readString(); + } + emit finished(this); + }); +}; +SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { +}; + +void SetMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + emit finished(this); + }); +}; + AssetClient::AssetClient() { @@ -39,7 +76,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingReply"); + packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingOperationReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); @@ -98,6 +135,33 @@ void AssetClient::clearCache() { } } +void AssetClient::handleAssetMappingOperationReply(QSharedPointer message, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + + AssetServerError error; + message->readPrimitive(&error); + + // Check if we have any pending requests for this node + auto messageMapIt = _pendingMappingRequests.find(senderNode); + if (messageMapIt != _pendingMappingRequests.end()) { + + // Found the node, get the MessageID -> Callback map + auto& messageCallbackMap = messageMapIt->second; + + // Check if we have this pending request + auto requestIt = messageCallbackMap.find(messageID); + if (requestIt != messageCallbackMap.end()) { + auto callback = requestIt->second; + callback(true, error, message); + messageCallbackMap.erase(requestIt); + } + + // Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from + // it to avoid constantly creating/deleting the map on subsequent requests. + } +} + bool haveAssetServer() { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -111,22 +175,15 @@ bool haveAssetServer() { return true; } -AssetRequest* AssetClient::createRequest(const QUrl& url) { - - auto parts = _url.path().split(".", QString::SkipEmptyParts); - auto hash = parts.length() > 0 ? parts[0] : ""; - auto extension = parts.length() > 1 ? parts[1] : ""; - - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; - - emit finished(); - return; - } - +GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { + return new GetMappingRequest(path); +} +SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) { + return new SetMappingRequest(path, hash); +} +AssetRequest* AssetClient::createRequest(const AssetHash& hash, const QString& extension) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; return nullptr; @@ -144,8 +201,6 @@ AssetRequest* AssetClient::createRequest(const QUrl& url) { } } - - AssetUpload* AssetClient::createUpload(const QString& filename) { if (haveAssetServer()) { @@ -171,34 +226,34 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } -bool AssetClient::getAssetMapping(const QString& path, GetMappingCallback callback) { - auto nodeList = DependencyManager::get(); - SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); - - if (assetServer) { - auto messageID = ++_currentID; - - auto payload = path.toLatin1(); - auto payloadSize = sizeof(messageID) + payload.size(); - auto packet = NLPacket::create(PacketType::AssetGetMapping, payloadSize, true); - - qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; - - packet->writePrimitive(messageID); - - auto bytesWritten = packet->write(payload); - Q_ASSERT(bytesWritten == payload.size()); - - nodeList->sendPacket(std::move(packet), *assetServer); - - _pendingMappingRequests[assetServer][messageID] = callback; - - return true; - } - - return false; -} - +//bool AssetClient::setAssetMapping(const QString& path, MappingOperationCallback callback) { +// auto nodeList = DependencyManager::get(); +// SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); +// +// if (assetServer) { +// auto messageID = ++_currentID; +// +// auto payload = path.toLatin1(); +// auto payloadSize = sizeof(messageID) + payload.size(); +// auto packet = NLPacket::create(PacketType::AssetMappingOperation, payloadSize, true); +// +// qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; +// +// packet->writePrimitive(messageID); +// +// auto bytesWritten = packet->write(payload); +// Q_ASSERT(bytesWritten == payload.size()); +// +// nodeList->sendPacket(std::move(packet), *assetServer); +// +// _pendingMappingRequests[assetServer][messageID] = callback; +// +// return true; +// } +// +// return false; +//} +// bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { @@ -264,39 +319,6 @@ bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, Ge return false; } - -void AssetClient::handleAssetGetMappingReply(QSharedPointer message, SharedNodePointer senderNode) { - MessageID messageID; - message->readPrimitive(&messageID); - - AssetServerError error; - message->readPrimitive(&error); - - QString assetHash; - if (error == AssetServerError::NoError) { - assetHash = message->read(SHA256_HASH_LENGTH); - } - - // Check if we have any pending requests for this node - auto messageMapIt = _pendingMappingRequests.find(senderNode); - if (messageMapIt != _pendingMappingRequests.end()) { - - // Found the node, get the MessageID -> Callback map - auto& messageCallbackMap = messageMapIt->second; - - // Check if we have this pending request - auto requestIt = messageCallbackMap.find(messageID); - if (requestIt != messageCallbackMap.end()) { - auto callback = requestIt->second; - callback(true, error, assetHash); - messageCallbackMap.erase(requestIt); - } - - // Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from - // it to avoid constantly creating/deleting the map on subsequent requests. - } -} - void AssetClient::handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; message->readPrimitive(&messageID); @@ -382,6 +404,55 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S } } +bool AssetClient::getAssetMapping(const AssetHash& hash, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Get); + + packetList->writeString(hash.toUtf8()); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + +bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Set); + + packetList->writeString(path.toUtf8()); + packetList->writeString(hash.toUtf8()); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); From 6dd3b1b4ee642117dd4f49e493d5639b6eeff513 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:27 -0800 Subject: [PATCH 005/258] Add AssetScriptingInterface methods for mapping --- libraries/networking/src/AssetClient.cpp | 37 ++++++++++++++- libraries/networking/src/AssetClient.h | 60 ++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index f3d677a98a..93139af2d0 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -619,4 +619,39 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb }); assetRequest->start(); -} \ No newline at end of file +} + +void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::getAllMappings(QString path, QScriptValue callback) { +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 1b74a47f99..0face50367 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -25,6 +25,8 @@ #include "ReceivedMessage.h" #include "ResourceCache.h" +class GetMappingRequest; +class SetMappingRequest; class AssetRequest; class AssetUpload; @@ -33,19 +35,61 @@ struct AssetInfo { int64_t size; }; +using MappingOperationCallback = std::function message)>; using ReceivedAssetCallback = std::function; -using MappingOperationCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; +class GetMappingRequest : public QObject { + Q_OBJECT +public: + GetMappingRequest(AssetPath path); + + Q_INVOKABLE void start(); + + AssetHash getHash() { return _hash; } + AssetServerError getError() { return _error; } + +signals: + void finished(GetMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetHash _hash; + AssetServerError _error { AssetServerError::NoError }; +}; + + +class SetMappingRequest : public QObject { + Q_OBJECT +public: + SetMappingRequest(AssetPath path, AssetHash hash); + + Q_INVOKABLE void start(); + + AssetHash getHash() { return _hash; } + AssetServerError getError() { return _error; } + +signals: + void finished(SetMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetHash _hash; + AssetServerError _error { AssetServerError::NoError }; +}; + + class AssetClient : public QObject, public Dependency { Q_OBJECT public: AssetClient(); - Q_INVOKABLE AssetRequest* createRequest(const QUrl& url); + Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); + Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); + Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash, const QString& extension); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); @@ -56,7 +100,7 @@ public slots: void clearCache(); private slots: - void handleAssetGetMappingReply(QSharedPointer message, SharedNodePointer senderNode); + void handleAssetMappingOperationReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode); @@ -64,7 +108,10 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: - bool getAssetMapping(const QString& path, MappingOperationCallback callback); + bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); + bool deleteAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); @@ -83,6 +130,8 @@ private: friend class AssetRequest; friend class AssetUpload; + friend class GetMappingRequest; + friend class SetMappingRequest; }; @@ -93,6 +142,9 @@ public: Q_INVOKABLE void uploadData(QString data, QString extension, QScriptValue callback); Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); + Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); + Q_INVOKABLE void getMapping(QString path, QScriptValue callback); + Q_INVOKABLE void getAllMappings(QString path, QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; From 2986aa1937e23203b1db21ce42279b3d6c08230f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:47 -0800 Subject: [PATCH 006/258] Revert AssetRequest back to using hash --- libraries/networking/src/AssetRequest.cpp | 4 ++-- libraries/networking/src/AssetRequest.h | 8 ++++---- libraries/networking/src/AssetResourceRequest.cpp | 14 +++++++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 505b64e080..0665590902 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -20,8 +20,8 @@ #include "NodeList.h" #include "ResourceCache.h" -AssetRequest::AssetRequest(const QString& url, const QString& extension) : - _url(url), +AssetRequest::AssetRequest(const QString& hash, const QString& extension) : + _hash(hash), _extension(extension) { } diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 288caac6df..049ab19ef4 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -39,7 +39,7 @@ public: UnknownError }; - AssetRequest(const QString& url, const QString& extension); + AssetRequest(const QString& hash, const QString& extension); Q_INVOKABLE void start(); @@ -52,15 +52,15 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); -private slots: - void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); +//private slots: + //void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); private: State _state = NotStarted; Error _error = NoError; AssetInfo _info; uint64_t _totalReceived { 0 }; - QString _url; + QString _hash; QString _extension; QByteArray _data; int _numPendingRequests { 0 }; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 0025ba565a..92a804d421 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -21,9 +21,21 @@ AssetResourceRequest::~AssetResourceRequest() { } void AssetResourceRequest::doSend() { + auto parts = _url.path().split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + auto extension = parts.length() > 1 ? parts[1] : ""; + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; + + emit finished(); + return; + } + // Make request to atp auto assetClient = DependencyManager::get(); - _assetRequest = assetClient->createRequest(_url); + _assetRequest = assetClient->createRequest(hash, extension); if (!_assetRequest) { _result = ServerUnavailable; From 292bc12f3740d8ca76bd0633b538204cb46addfa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:24:12 -0800 Subject: [PATCH 007/258] Add read/writeString to PacketList and Packet --- libraries/networking/src/AssetUtils.h | 3 +++ libraries/networking/src/ReceivedMessage.cpp | 4 ++-- libraries/networking/src/ReceivedMessage.h | 1 - libraries/networking/src/udt/BasePacket.cpp | 14 ++++++++++++++ libraries/networking/src/udt/BasePacket.h | 5 ++++- libraries/networking/src/udt/PacketList.cpp | 6 ++++++ libraries/networking/src/udt/PacketList.h | 2 ++ 7 files changed, 31 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 58e7aa6146..f13c9ac729 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -20,6 +20,9 @@ using MessageID = uint32_t; using DataOffset = int64_t; +using AssetPath = QString; +using AssetHash = QString; + const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index eed275dc1a..6ef2b7c7d4 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -110,8 +110,8 @@ QByteArray ReceivedMessage::readAll() { QString ReceivedMessage::readString() { uint32_t size; readPrimitive(&size); - Q_ASSERT(size <= _size - _position); - auto string = QString::fromUtf8(_data.constData(), size); + //Q_ASSERT(size <= _size - _position); + auto string = QString::fromUtf8(_data.constData() + _position, size); _position += size; return string; } diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index b813149bed..e9131c074f 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -88,7 +88,6 @@ private: QByteArray _data; QByteArray _headData; - std::atomic _size { true }; std::atomic _position { 0 }; std::atomic _numPackets { 0 }; diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 000573d241..e0b2a8ba3a 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -150,6 +150,20 @@ QByteArray BasePacket::readWithoutCopy(qint64 maxSize) { return data; } +qint64 BasePacket::writeString(const QString& string) { + QByteArray data = string.toUtf8(); + writePrimitive(static_cast(data.length())); + return writeData(data.constData(), data.length()); +} + +QString BasePacket::readString() { + uint32_t size {}; + readPrimitive(&size); + auto string = QString::fromUtf8(getPayload() + pos(), size); + seek(pos() + size); + return string; +} + bool BasePacket::reset() { if (isWritable()) { _payloadSize = 0; diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index 392a7c4384..846c05ecbf 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -77,7 +77,10 @@ public: using QIODevice::read; // Bring QIODevice::read methods to scope, otherwise they are hidden by folling method QByteArray read(qint64 maxSize); QByteArray readWithoutCopy(qint64 maxSize); // this can only be used if packet will stay in scope - + + qint64 writeString(const QString& string); + QString readString(); + template qint64 peekPrimitive(T* data); template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 978df9b9bb..b12b7e6938 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -158,6 +158,12 @@ void PacketList::preparePackets(MessageNumber messageNumber) { const qint64 PACKET_LIST_WRITE_ERROR = -1; +qint64 PacketList::writeString(const QString& string) { + QByteArray data = string.toUtf8(); + writePrimitive(static_cast(data.length())); + return writeData(data.constData(), data.length()); +} + qint64 PacketList::writeData(const char* data, qint64 maxSize) { auto sizeRemaining = maxSize; diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 4f1e46e616..875eb70e45 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -59,6 +59,8 @@ public: template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); + + qint64 writeString(const QString& string); protected: PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false); From 6b485cf81d4bd851267b3460cbc257a4043f8e1d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Mar 2016 16:18:35 -0800 Subject: [PATCH 008/258] Update atp mapping operations to use a single packet --- assignment-client/src/assets/AssetServer.cpp | 59 ++++++++++++++++++++ assignment-client/src/assets/AssetServer.h | 16 ++++++ libraries/networking/src/AssetClient.cpp | 4 +- libraries/networking/src/AssetClient.h | 3 + libraries/networking/src/AssetUtils.h | 6 ++ libraries/networking/src/ReceivedMessage.cpp | 9 +++ libraries/networking/src/ReceivedMessage.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 4 +- 8 files changed, 101 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4ca2439996..84a3feaabc 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -42,6 +42,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); + packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOpertation"); } void AssetServer::run() { @@ -161,6 +162,52 @@ void AssetServer::completeSetup() { nodeList->addNodeTypeToInterestSet(NodeType::Agent); } +void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + + AssetMappingOperationType operationType; + message->readPrimitive(&operationType); + + auto replyPacket = NLPacket::create(PacketType::AssetMappingOperationReply); + replyPacket->writePrimitive(messageID); + + switch (operationType) { + case AssetMappingOperationType::Get: { + QString assetPath = message->readString(); + + auto it = _fileMapping.find(assetPath); + if (it != _fileMapping.end()) { + auto assetHash = it->second; + qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(assetHash.toLatin1().toHex()); + } + else { + qDebug() << "Mapping not found for: " << assetPath; + replyPacket->writePrimitive(AssetServerError::AssetNotFound); + } + } + case AssetMappingOperationType::Set: { + QString assetPath = message->readString(); + auto assetHash = message->read(SHA256_HASH_LENGTH); + _fileMapping[assetPath] = assetHash; + + replyPacket->writePrimitive(AssetServerError::NoError); + } + case AssetMappingOperationType::Delete: { + QString assetPath = message->readString(); + bool removed = _fileMapping.erase(assetPath) > 0; + + replyPacket->writePrimitive(AssetServerError::NoError); + } + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(replyPacket), *senderNode); +} + +>>>>>>> db98e46... Update atp mapping operations to use a single packet void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; @@ -308,3 +355,15 @@ void AssetServer::sendStatsPacket() { // send off the stats packets ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } + +AssetServer::Hash AssetServer::getMapping(Path path) { + return _fileMapping[path]; +} + +void AssetServer::setMapping(Path path, Hash hash) { + _fileMapping[path] = hash; +} + +bool AssetServer::deleteMapping(Path path) { + return _fileMapping.erase(path) > 0; +} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 7d6e26af08..5287c222aa 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -34,11 +34,27 @@ private slots: void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); + void handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode); void sendStatsPacket(); private: + using Path = QString; + using Hash = QString; + using Mapping = std::unordered_map; + + /// Return the hash mapping for Path `path` + Hash getMapping(Path path); + + /// Set the mapping for path to hash + void setMapping(Path path, Hash hash); + + /// Delete mapping `path`. Return `true` if mapping existed, else `false`. + bool deleteMapping(Path path); + static void writeError(NLPacketList* packetList, AssetServerError error); + + Mapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 9591828fef..d658855e1f 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -39,6 +39,8 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); + + packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); @@ -471,4 +473,4 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb }); assetRequest->start(); -} \ No newline at end of file +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f66fe8adcc..16bd0a4e04 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -34,6 +34,7 @@ struct AssetInfo { }; using ReceivedAssetCallback = std::function; +using MappingOperationCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; @@ -62,6 +63,7 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: + bool getAssetMapping(const QString& path, MappingOperationCallback callback); bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); @@ -73,6 +75,7 @@ private: }; static MessageID _currentID; + std::unordered_map> _pendingMappingRequests; std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 21b6b3f434..58e7aa6146 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -32,6 +32,12 @@ enum AssetServerError : uint8_t { PermissionDenied }; +enum AssetMappingOperationType : uint8_t { + Get = 0, + Set, + Delete +}; + QUrl getATPUrl(const QString& hash, const QString& extension = QString()); QByteArray hashData(const QByteArray& data); diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index 651b856923..eed275dc1a 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -107,6 +107,15 @@ QByteArray ReceivedMessage::readAll() { return read(getBytesLeftToRead()); } +QString ReceivedMessage::readString() { + uint32_t size; + readPrimitive(&size); + Q_ASSERT(size <= _size - _position); + auto string = QString::fromUtf8(_data.constData(), size); + _position += size; + return string; +} + QByteArray ReceivedMessage::readWithoutCopy(qint64 size) { QByteArray data { QByteArray::fromRawData(_data.constData() + _position, size) }; _position += size; diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index 1f797f1262..b813149bed 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -63,6 +63,8 @@ public: QByteArray read(qint64 size); QByteArray readAll(); + QString readString(); + QByteArray readHead(qint64 size); // This will return a QByteArray referencing the underlying data _without_ refcounting that data. diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 7840ecb17e..a2bd0d4d2d 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -91,7 +91,9 @@ public: MessagesData, MessagesSubscribe, MessagesUnsubscribe, - ICEServerHeartbeatDenied + ICEServerHeartbeatDenied, + AssetMappingOperation, + AssetMappingOperationReply }; }; From 9eb0fdf589aee092138e02af51e8be2f46a9a0aa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:22:23 -0800 Subject: [PATCH 009/258] Clean up AssetServer mapping handling --- assignment-client/src/assets/AssetServer.cpp | 23 +++++++++++++++----- assignment-client/src/assets/AssetServer.h | 15 +++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 84a3feaabc..dbee3cd547 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -42,7 +42,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); - packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOpertation"); + packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation"); } void AssetServer::run() { @@ -181,25 +181,30 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me auto assetHash = it->second; qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(assetHash.toLatin1().toHex()); + //replyPacket->write(assetHash.toLatin1().toHex()); + replyPacket->writeString(assetHash.toLatin1()); } else { qDebug() << "Mapping not found for: " << assetPath; replyPacket->writePrimitive(AssetServerError::AssetNotFound); } + break; } case AssetMappingOperationType::Set: { QString assetPath = message->readString(); - auto assetHash = message->read(SHA256_HASH_LENGTH); + //auto assetHash = message->read(SHA256_HASH_LENGTH); + auto assetHash = message->readString(); _fileMapping[assetPath] = assetHash; replyPacket->writePrimitive(AssetServerError::NoError); + break; } case AssetMappingOperationType::Delete: { QString assetPath = message->readString(); bool removed = _fileMapping.erase(assetPath) > 0; replyPacket->writePrimitive(AssetServerError::NoError); + break; } } @@ -356,14 +361,20 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } -AssetServer::Hash AssetServer::getMapping(Path path) { +void AssetServer::loadMappingFromFile() { +} + +void AssetServer::writeMappingToFile() { +} + +AssetHash AssetServer::getMapping(AssetPath path) { return _fileMapping[path]; } -void AssetServer::setMapping(Path path, Hash hash) { +void AssetServer::setMapping(AssetPath path, AssetHash hash) { _fileMapping[path] = hash; } -bool AssetServer::deleteMapping(Path path) { +bool AssetServer::deleteMapping(AssetPath path) { return _fileMapping.erase(path) > 0; } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 5287c222aa..1eee4feb94 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,18 +39,19 @@ private slots: void sendStatsPacket(); private: - using Path = QString; - using Hash = QString; - using Mapping = std::unordered_map; + using Mapping = std::map; - /// Return the hash mapping for Path `path` - Hash getMapping(Path path); + void loadMappingFromFile(); + void writeMappingToFile(); + + /// Return the hash mapping for AssetPath `path` + AssetHash getMapping(AssetPath path); /// Set the mapping for path to hash - void setMapping(Path path, Hash hash); + void setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Return `true` if mapping existed, else `false`. - bool deleteMapping(Path path); + bool deleteMapping(AssetPath path); static void writeError(NLPacketList* packetList, AssetServerError error); From 462f00077c39b3f4262e6c55d1798b31630d58cc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:00 -0800 Subject: [PATCH 010/258] Add get/set mapping request --- libraries/networking/src/AssetClient.cpp | 156 ++++++++++++++++++++++- 1 file changed, 152 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d658855e1f..91d35701bf 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -30,6 +30,43 @@ MessageID AssetClient::_currentID = 0; +GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { +}; + +void GetMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->getAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + if (!error) { + //_hash = message->read(SHA256_HASH_HEX_LENGTH); + _hash = message->readString(); + } + emit finished(this); + }); +}; +SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { +}; + +void SetMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + emit finished(this); + }); +}; + AssetClient::AssetClient() { @@ -40,7 +77,7 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingReply"); + packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingOperationReply"); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); @@ -99,6 +136,33 @@ void AssetClient::clearCache() { } } +void AssetClient::handleAssetMappingOperationReply(QSharedPointer message, SharedNodePointer senderNode) { + MessageID messageID; + message->readPrimitive(&messageID); + + AssetServerError error; + message->readPrimitive(&error); + + // Check if we have any pending requests for this node + auto messageMapIt = _pendingMappingRequests.find(senderNode); + if (messageMapIt != _pendingMappingRequests.end()) { + + // Found the node, get the MessageID -> Callback map + auto& messageCallbackMap = messageMapIt->second; + + // Check if we have this pending request + auto requestIt = messageCallbackMap.find(messageID); + if (requestIt != messageCallbackMap.end()) { + auto callback = requestIt->second; + callback(true, error, message); + messageCallbackMap.erase(requestIt); + } + + // Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from + // it to avoid constantly creating/deleting the map on subsequent requests. + } +} + bool haveAssetServer() { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -112,7 +176,15 @@ bool haveAssetServer() { return true; } -AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) { +GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { + return new GetMappingRequest(path); +} + +SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) { + return new SetMappingRequest(path, hash); +} + +AssetRequest* AssetClient::createRequest(const AssetHash& hash, const QString& extension) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; return nullptr; @@ -130,8 +202,6 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext } } - - AssetUpload* AssetClient::createUpload(const QString& filename) { if (haveAssetServer()) { @@ -157,6 +227,35 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } +//bool AssetClient::setAssetMapping(const QString& path, MappingOperationCallback callback) { +// auto nodeList = DependencyManager::get(); +// SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); +// +// if (assetServer) { +// auto messageID = ++_currentID; +// +// auto payload = path.toLatin1(); +// auto payloadSize = sizeof(messageID) + payload.size(); +// auto packet = NLPacket::create(PacketType::AssetMappingOperation, payloadSize, true); +// +// qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; +// +// packet->writePrimitive(messageID); +// +// auto bytesWritten = packet->write(payload); +// Q_ASSERT(bytesWritten == payload.size()); +// +// nodeList->sendPacket(std::move(packet), *assetServer); +// +// _pendingMappingRequests[assetServer][messageID] = callback; +// +// return true; +// } +// +// return false; +//} +// + bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { @@ -307,6 +406,55 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S } } +bool AssetClient::getAssetMapping(const AssetHash& hash, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Get); + + packetList->writeString(hash.toUtf8()); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + +bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Set); + + packetList->writeString(path.toUtf8()); + packetList->writeString(hash.toUtf8()); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); From 7dd436a7a81afe7a873f3f04d561569b362c61f6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:27 -0800 Subject: [PATCH 011/258] Add AssetScriptingInterface methods for mapping --- libraries/networking/src/AssetClient.cpp | 36 +++++++++++++++ libraries/networking/src/AssetClient.h | 59 ++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 91d35701bf..472cbaab6e 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -622,3 +622,39 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb assetRequest->start(); } + +void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::getAllMappings(QString path, QScriptValue callback) { +} +>>>>>>> 6dd3b1b... Add AssetScriptingInterface methods for mapping diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 16bd0a4e04..0face50367 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -25,6 +25,8 @@ #include "ReceivedMessage.h" #include "ResourceCache.h" +class GetMappingRequest; +class SetMappingRequest; class AssetRequest; class AssetUpload; @@ -33,19 +35,61 @@ struct AssetInfo { int64_t size; }; +using MappingOperationCallback = std::function message)>; using ReceivedAssetCallback = std::function; -using MappingOperationCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; using ProgressCallback = std::function; +class GetMappingRequest : public QObject { + Q_OBJECT +public: + GetMappingRequest(AssetPath path); + + Q_INVOKABLE void start(); + + AssetHash getHash() { return _hash; } + AssetServerError getError() { return _error; } + +signals: + void finished(GetMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetHash _hash; + AssetServerError _error { AssetServerError::NoError }; +}; + + +class SetMappingRequest : public QObject { + Q_OBJECT +public: + SetMappingRequest(AssetPath path, AssetHash hash); + + Q_INVOKABLE void start(); + + AssetHash getHash() { return _hash; } + AssetServerError getError() { return _error; } + +signals: + void finished(SetMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetHash _hash; + AssetServerError _error { AssetServerError::NoError }; +}; + + class AssetClient : public QObject, public Dependency { Q_OBJECT public: AssetClient(); - Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension); + Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); + Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); + Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash, const QString& extension); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); @@ -56,6 +100,7 @@ public slots: void clearCache(); private slots: + void handleAssetMappingOperationReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode); @@ -63,7 +108,10 @@ private slots: void handleNodeKilled(SharedNodePointer node); private: - bool getAssetMapping(const QString& path, MappingOperationCallback callback); + bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); + bool deleteAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); @@ -82,6 +130,8 @@ private: friend class AssetRequest; friend class AssetUpload; + friend class GetMappingRequest; + friend class SetMappingRequest; }; @@ -92,6 +142,9 @@ public: Q_INVOKABLE void uploadData(QString data, QString extension, QScriptValue callback); Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); + Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); + Q_INVOKABLE void getMapping(QString path, QScriptValue callback); + Q_INVOKABLE void getAllMappings(QString path, QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; From 7317d3b2ea8de77baf8ee4e9be18d8fa56531912 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:23:47 -0800 Subject: [PATCH 012/258] Revert AssetRequest back to using hash --- libraries/networking/src/AssetRequest.cpp | 1 - libraries/networking/src/AssetRequest.h | 3 +++ libraries/networking/src/AssetResourceRequest.cpp | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 19f91349fb..0665590902 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -21,7 +21,6 @@ #include "ResourceCache.h" AssetRequest::AssetRequest(const QString& hash, const QString& extension) : - QObject(), _hash(hash), _extension(extension) { diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 3c3459b15d..049ab19ef4 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -52,6 +52,9 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); +//private slots: + //void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); + private: State _state = NotStarted; Error _error = NoError; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index dac3329153..92a804d421 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -21,8 +21,6 @@ AssetResourceRequest::~AssetResourceRequest() { } void AssetResourceRequest::doSend() { - // Make request to atp - auto assetClient = DependencyManager::get(); auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; auto extension = parts.length() > 1 ? parts[1] : ""; @@ -35,6 +33,8 @@ void AssetResourceRequest::doSend() { return; } + // Make request to atp + auto assetClient = DependencyManager::get(); _assetRequest = assetClient->createRequest(hash, extension); if (!_assetRequest) { From 19cd352a77aa1b979407f39f89bb5b0fedd389b2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 13:24:12 -0800 Subject: [PATCH 013/258] Add read/writeString to PacketList and Packet --- libraries/networking/src/AssetUtils.h | 3 +++ libraries/networking/src/ReceivedMessage.cpp | 4 ++-- libraries/networking/src/ReceivedMessage.h | 1 - libraries/networking/src/udt/BasePacket.cpp | 14 ++++++++++++++ libraries/networking/src/udt/BasePacket.h | 5 ++++- libraries/networking/src/udt/PacketList.cpp | 6 ++++++ libraries/networking/src/udt/PacketList.h | 2 ++ 7 files changed, 31 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 58e7aa6146..f13c9ac729 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -20,6 +20,9 @@ using MessageID = uint32_t; using DataOffset = int64_t; +using AssetPath = QString; +using AssetHash = QString; + const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index eed275dc1a..6ef2b7c7d4 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -110,8 +110,8 @@ QByteArray ReceivedMessage::readAll() { QString ReceivedMessage::readString() { uint32_t size; readPrimitive(&size); - Q_ASSERT(size <= _size - _position); - auto string = QString::fromUtf8(_data.constData(), size); + //Q_ASSERT(size <= _size - _position); + auto string = QString::fromUtf8(_data.constData() + _position, size); _position += size; return string; } diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index b813149bed..e9131c074f 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -88,7 +88,6 @@ private: QByteArray _data; QByteArray _headData; - std::atomic _size { true }; std::atomic _position { 0 }; std::atomic _numPackets { 0 }; diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 000573d241..e0b2a8ba3a 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -150,6 +150,20 @@ QByteArray BasePacket::readWithoutCopy(qint64 maxSize) { return data; } +qint64 BasePacket::writeString(const QString& string) { + QByteArray data = string.toUtf8(); + writePrimitive(static_cast(data.length())); + return writeData(data.constData(), data.length()); +} + +QString BasePacket::readString() { + uint32_t size {}; + readPrimitive(&size); + auto string = QString::fromUtf8(getPayload() + pos(), size); + seek(pos() + size); + return string; +} + bool BasePacket::reset() { if (isWritable()) { _payloadSize = 0; diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index 392a7c4384..846c05ecbf 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -77,7 +77,10 @@ public: using QIODevice::read; // Bring QIODevice::read methods to scope, otherwise they are hidden by folling method QByteArray read(qint64 maxSize); QByteArray readWithoutCopy(qint64 maxSize); // this can only be used if packet will stay in scope - + + qint64 writeString(const QString& string); + QString readString(); + template qint64 peekPrimitive(T* data); template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 978df9b9bb..b12b7e6938 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -158,6 +158,12 @@ void PacketList::preparePackets(MessageNumber messageNumber) { const qint64 PACKET_LIST_WRITE_ERROR = -1; +qint64 PacketList::writeString(const QString& string) { + QByteArray data = string.toUtf8(); + writePrimitive(static_cast(data.length())); + return writeData(data.constData(), data.length()); +} + qint64 PacketList::writeData(const char* data, qint64 maxSize) { auto sizeRemaining = maxSize; diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 4f1e46e616..875eb70e45 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -59,6 +59,8 @@ public: template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); + + qint64 writeString(const QString& string); protected: PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false); From 267ed3af822bbd33d8d2071ce4fd9b723431cc2c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 11:56:00 -0800 Subject: [PATCH 014/258] remove client side handling of extension for ATP hash URLs --- interface/src/assets/ATPAssetMigrator.cpp | 2 +- libraries/networking/src/AssetClient.cpp | 50 +++---------------- libraries/networking/src/AssetClient.h | 6 +-- libraries/networking/src/AssetRequest.cpp | 9 ++-- libraries/networking/src/AssetRequest.h | 5 +- .../networking/src/AssetResourceRequest.cpp | 36 +++++++++++-- libraries/networking/src/AssetUpload.cpp | 2 +- libraries/networking/src/AssetUtils.cpp | 8 +-- libraries/networking/src/AssetUtils.h | 2 +- .../networking/src/udt/PacketHeaders.cpp | 4 ++ 10 files changed, 57 insertions(+), 67 deletions(-) diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index f037cf9f91..dba2047da1 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -173,7 +173,7 @@ void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& h auto values = _pendingReplacements.values(modelURL); - QString atpURL = getATPUrl(hash, upload->getExtension()).toString(); + QString atpURL = getATPUrl(hash).toString(); for (auto value : values) { // replace the modelURL in this QJsonValueRef with the hash diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 472cbaab6e..51c5ae8cb3 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -184,14 +184,14 @@ SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, c return new SetMappingRequest(path, hash); } -AssetRequest* AssetClient::createRequest(const AssetHash& hash, const QString& extension) { +AssetRequest* AssetClient::createRequest(const AssetHash& hash) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; return nullptr; } if (haveAssetServer()) { - auto request = new AssetRequest(hash, extension); + auto request = new AssetRequest(hash); // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case) request->moveToThread(thread()); @@ -227,36 +227,7 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } -//bool AssetClient::setAssetMapping(const QString& path, MappingOperationCallback callback) { -// auto nodeList = DependencyManager::get(); -// SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); -// -// if (assetServer) { -// auto messageID = ++_currentID; -// -// auto payload = path.toLatin1(); -// auto payloadSize = sizeof(messageID) + payload.size(); -// auto packet = NLPacket::create(PacketType::AssetMappingOperation, payloadSize, true); -// -// qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; -// -// packet->writePrimitive(messageID); -// -// auto bytesWritten = packet->write(payload); -// Q_ASSERT(bytesWritten == payload.size()); -// -// nodeList->sendPacket(std::move(packet), *assetServer); -// -// _pendingMappingRequests[assetServer][messageID] = callback; -// -// return true; -// } -// -// return false; -//} -// - -bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, +bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; @@ -270,8 +241,7 @@ bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOf auto messageID = ++_currentID; - auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + extension.length() - + sizeof(start) + sizeof(end); + auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(start) + sizeof(end); auto packet = NLPacket::create(PacketType::AssetGet, payloadSize, true); qCDebug(asset_client) << "Requesting data from" << start << "to" << end << "of" << hash << "from asset-server."; @@ -280,9 +250,6 @@ bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOf packet->write(QByteArray::fromHex(hash.toLatin1())); - packet->writePrimitive(uint8_t(extension.length())); - packet->write(extension.toLatin1()); - packet->writePrimitive(start); packet->writePrimitive(end); @@ -296,20 +263,18 @@ bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOf return false; } -bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback) { +bool AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { auto messageID = ++_currentID; - auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + extension.length(); + auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH; auto packet = NLPacket::create(PacketType::AssetGetInfo, payloadSize, true); packet->writePrimitive(messageID); packet->write(QByteArray::fromHex(hash.toLatin1())); - packet->writePrimitive(uint8_t(extension.length())); - packet->write(extension.toLatin1()); nodeList->sendPacket(std::move(packet), *assetServer); @@ -590,14 +555,13 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb auto path = urlString.right(urlString.length() - ATP_SCHEME.length()); auto parts = path.split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; - auto extension = parts.length() > 1 ? parts[1] : ""; if (hash.length() != SHA256_HASH_HEX_LENGTH) { return; } auto assetClient = DependencyManager::get(); - auto assetRequest = assetClient->createRequest(hash, extension); + auto assetRequest = assetClient->createRequest(hash); if (!assetRequest) { return; diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 0face50367..60a6815a53 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -89,7 +89,7 @@ public: Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); - Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash, const QString& extension); + Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); @@ -112,8 +112,8 @@ private: bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); bool deleteAssetMapping(const AssetHash& hash, MappingOperationCallback callback); - bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); - bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, + bool getAssetInfo(const QString& hash, GetInfoCallback callback); + bool getAsset(const QString& hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); bool uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback); diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 0665590902..f2e347e0f7 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -20,9 +20,8 @@ #include "NodeList.h" #include "ResourceCache.h" -AssetRequest::AssetRequest(const QString& hash, const QString& extension) : - _hash(hash), - _extension(extension) +AssetRequest::AssetRequest(const QString& hash) : + _hash(hash) { } @@ -52,7 +51,7 @@ void AssetRequest::start() { _state = WaitingForInfo; auto assetClient = DependencyManager::get(); - assetClient->getAssetInfo(_hash, _extension, [this](bool responseReceived, AssetServerError serverError, AssetInfo info) { + assetClient->getAssetInfo(_hash, [this](bool responseReceived, AssetServerError serverError, AssetInfo info) { _info = info; if (!responseReceived) { @@ -84,7 +83,7 @@ void AssetRequest::start() { int start = 0, end = _info.size; auto assetClient = DependencyManager::get(); - assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool responseReceived, AssetServerError serverError, + assetClient->getAsset(_hash, start, end, [this, start, end](bool responseReceived, AssetServerError serverError, const QByteArray& data) { if (!responseReceived) { _error = NetworkError; diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 049ab19ef4..4c35a46fe7 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -39,14 +39,14 @@ public: UnknownError }; - AssetRequest(const QString& hash, const QString& extension); + AssetRequest(const QString& hash); Q_INVOKABLE void start(); const QByteArray& getData() const { return _data; } const State& getState() const { return _state; } const Error& getError() const { return _error; } - QUrl getUrl() const { return ::getATPUrl(_hash, _extension); } + QUrl getUrl() const { return ::getATPUrl(_hash); } signals: void finished(AssetRequest* thisRequest); @@ -61,7 +61,6 @@ private: AssetInfo _info; uint64_t _totalReceived { 0 }; QString _hash; - QString _extension; QByteArray _data; int _numPendingRequests { 0 }; }; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 92a804d421..07fc5920ee 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -20,14 +20,42 @@ AssetResourceRequest::~AssetResourceRequest() { } } +bool AssetResourceRequest::urlIsAssetPath() const { + static const QString ATP_HASH_REGEX_STRING = "^atp:([A-Fa-f0-9]{64})(\\.[\\w]+)?$"; + + QRegExp hashRegex { ATP_HASH_REGEX_STRING }; + return !hashRegex.exactMatch(_url.toString()); +} + void AssetResourceRequest::doSend() { auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; auto extension = parts.length() > 1 ? parts[1] : ""; - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; + // We'll either have a hash or an ATP path to a file (that maps to a hash) + + if (urlIsAssetPath()) { + // This is an ATP path, we'll need to figure out what the mapping is. + // This may incur a roundtrip to the asset-server, or it may return immediately from the cache in AssetClient. + + qDebug() << "Detected an asset path! URL is" << _url; + } else { + + qDebug() << "ATP URL was not an asset path - url is" << _url.toString(); + + // We've detected that this is a hash - simply use AssetClient to request that asset + auto parts = _url.path().split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + auto extension = parts.length() > 1 ? parts[1] : ""; + + // in case we haven't parsed a valid hash, return an error now + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; + + emit finished(); + return; + } emit finished(); return; @@ -35,7 +63,7 @@ void AssetResourceRequest::doSend() { // Make request to atp auto assetClient = DependencyManager::get(); - _assetRequest = assetClient->createRequest(hash, extension); + _assetRequest = assetClient->createRequest(hash); if (!_assetRequest) { _result = ServerUnavailable; diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 2d6f0c0e97..1189c341b1 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -103,7 +103,7 @@ void AssetUpload::start() { } if (_error == NoError && hash == hashData(_data).toHex()) { - saveToCache(getATPUrl(hash, _extension), _data); + saveToCache(getATPUrl(hash), _data); } emit finished(this, hash); diff --git a/libraries/networking/src/AssetUtils.cpp b/libraries/networking/src/AssetUtils.cpp index f37e0af820..cf1bdbe8f2 100644 --- a/libraries/networking/src/AssetUtils.cpp +++ b/libraries/networking/src/AssetUtils.cpp @@ -19,12 +19,8 @@ #include "ResourceManager.h" -QUrl getATPUrl(const QString& hash, const QString& extension) { - if (!extension.isEmpty()) { - return QUrl(QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, extension)); - } else { - return QUrl(QString("%1:%2").arg(URL_SCHEME_ATP, hash)); - } +QUrl getATPUrl(const QString& hash) { + return QUrl(QString("%1:%2").arg(URL_SCHEME_ATP, hash)); } QByteArray hashData(const QByteArray& data) { diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index f13c9ac729..cc9aa60407 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -41,7 +41,7 @@ enum AssetMappingOperationType : uint8_t { Delete }; -QUrl getATPUrl(const QString& hash, const QString& extension = QString()); +QUrl getATPUrl(const QString& hash); QByteArray hashData(const QByteArray& data); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 3ffbb867bf..2c53e01b2a 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -53,6 +53,10 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(AvatarMixerPacketVersion::SoftAttachmentSupport); case PacketType::ICEServerHeartbeat: return 18; // ICE Server Heartbeat signing + case PacketType::AssetGetInfo: + case PacketType::AssetGet: + // Introduction of ATP Mappings + return 18; default: return 17; } From e7124d4b10e6b864bbb67f2d31e5bcd874e2dec2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 12:15:22 -0800 Subject: [PATCH 015/258] add server handling for no extension requests --- assignment-client/src/assets/AssetServer.cpp | 40 +++++-------------- .../src/assets/SendAssetTask.cpp | 5 +-- 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index dbee3cd547..15dfb95551 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -130,34 +130,15 @@ void AssetServer::completeSetup() { } } - qDebug() << "Serving files from: " << _resourcesDirectory.path(); + qInfo() << "Serving files from: " << _resourcesDirectory.path(); - // Scan for new files - qDebug() << "Looking for new files in asset directory"; - auto files = _resourcesDirectory.entryInfoList(QDir::Files); - QRegExp filenameRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}(\\..+)?$" }; - for (const auto& fileInfo : files) { - auto filename = fileInfo.fileName(); - if (!filenameRegex.exactMatch(filename)) { - qDebug() << "Found file: " << filename; - if (!fileInfo.isReadable()) { - qDebug() << "\tCan't open file for reading: " << filename; - continue; - } + // Check the asset directory to output some information about what we have + auto files = _resourcesDirectory.entryList(QDir::Files); - // Read file - QFile file { fileInfo.absoluteFilePath() }; - file.open(QFile::ReadOnly); - QByteArray data = file.readAll(); + QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; + auto hashedFiles = files.filter(hashFileRegex); - auto hash = hashData(data); - auto hexHash = hash.toHex(); - - qDebug() << "\tMoving " << filename << " to " << hexHash; - - file.rename(_resourcesDirectory.absoluteFilePath(hexHash) + "." + fileInfo.suffix()); - } - } + qInfo() << "There are" << hashedFiles.size() << "asset files in the asset directory."; nodeList->addNodeTypeToInterestSet(NodeType::Agent); } @@ -216,17 +197,14 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; - uint8_t extensionLength; - if (message->getSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { + if (message->getSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID))) { qDebug() << "ERROR bad file request"; return; } message->readPrimitive(&messageID); assetHash = message->readWithoutCopy(SHA256_HASH_LENGTH); - message->readPrimitive(&extensionLength); - QByteArray extension = message->read(extensionLength); auto replyPacket = NLPacket::create(PacketType::AssetGetInfoReply); @@ -235,7 +213,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh replyPacket->writePrimitive(messageID); replyPacket->write(assetHash); - QString fileName = QString(hexHash) + "." + extension; + QString fileName = QString(hexHash); QFileInfo fileInfo { _resourcesDirectory.filePath(fileName) }; if (fileInfo.exists() && fileInfo.isReadable()) { @@ -253,7 +231,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh void AssetServer::handleAssetGet(QSharedPointer message, SharedNodePointer senderNode) { - auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + sizeof(DataOffset) + sizeof(DataOffset)); + auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(DataOffset) + sizeof(DataOffset)); if (message->getSize() < minSize) { qDebug() << "ERROR bad file request"; diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 35f4ad1801..33e1ab0fb8 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -33,13 +33,10 @@ SendAssetTask::SendAssetTask(QSharedPointer message, const Shar void SendAssetTask::run() { MessageID messageID; - uint8_t extensionLength; DataOffset start, end; _message->readPrimitive(&messageID); QByteArray assetHash = _message->read(SHA256_HASH_LENGTH); - _message->readPrimitive(&extensionLength); - QByteArray extension = _message->read(extensionLength); // `start` and `end` indicate the range of data to retrieve for the asset identified by `assetHash`. // `start` is inclusive, `end` is exclusive. Requesting `start` = 1, `end` = 10 will retrieve 9 bytes of data, @@ -61,7 +58,7 @@ void SendAssetTask::run() { if (end <= start) { writeError(replyPacketList.get(), AssetServerError::InvalidByteRange); } else { - QString filePath = _resourcesDir.filePath(QString(hexHash) + "." + QString(extension)); + QString filePath = _resourcesDir.filePath(QString(hexHash)); QFile file { filePath }; From 7bb97ec3da0483103056c1be5354dcb9b0315fd6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 13:25:28 -0800 Subject: [PATCH 016/258] add an extra space before debug in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 15dfb95551..2777496d97 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -130,6 +130,7 @@ void AssetServer::completeSetup() { } } + qInfo() << "Serving files from: " << _resourcesDirectory.path(); // Check the asset directory to output some information about what we have From e6ce5170418682d9d96e006178996cc2ec84176f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 13:57:41 -0800 Subject: [PATCH 017/258] remove committed version control marker --- libraries/networking/src/AssetClient.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 51c5ae8cb3..deb1d9eb7d 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -621,4 +621,3 @@ void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { void AssetScriptingInterface::getAllMappings(QString path, QScriptValue callback) { } ->>>>>>> 6dd3b1b... Add AssetScriptingInterface methods for mapping From 4bf69f20b7bc789c2d46b44bfad460bd1ad4087d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 13:59:17 -0800 Subject: [PATCH 018/258] fix removal of requestHash method during cherry-pick --- .../networking/src/AssetResourceRequest.cpp | 17 +++++++++-------- libraries/networking/src/AssetResourceRequest.h | 4 ++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 07fc5920ee..10c50c0b87 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -46,16 +46,17 @@ void AssetResourceRequest::doSend() { // We've detected that this is a hash - simply use AssetClient to request that asset auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; - auto extension = parts.length() > 1 ? parts[1] : ""; - // in case we haven't parsed a valid hash, return an error now - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; + requestHash(hash); + } +} - emit finished(); - return; - } +void AssetResourceRequest::requestHash(const QString& hash) { + + // in case we haven't parsed a valid hash, return an error now + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; emit finished(); return; diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 4d2ea56ca4..d74991ad6a 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -30,6 +30,10 @@ private slots: void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); private: + bool urlIsAssetPath() const; + + void requestHash(const QString& hash); + AssetRequest* _assetRequest { nullptr }; }; From 83b563cf9c95cc75786dc5ddcdaa6940d92f3b54 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 14:00:12 -0800 Subject: [PATCH 019/258] use AssetHash alias for hash in AssetResourceRequest --- libraries/networking/src/AssetResourceRequest.cpp | 2 +- libraries/networking/src/AssetResourceRequest.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 10c50c0b87..c9ac06fca4 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -51,7 +51,7 @@ void AssetResourceRequest::doSend() { } } -void AssetResourceRequest::requestHash(const QString& hash) { +void AssetResourceRequest::requestHash(const AssetHash& hash) { // in case we haven't parsed a valid hash, return an error now if (hash.length() != SHA256_HASH_HEX_LENGTH) { diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index d74991ad6a..c9a1fbfbf9 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -32,7 +32,7 @@ private slots: private: bool urlIsAssetPath() const; - void requestHash(const QString& hash); + void requestHash(const AssetHash& hash); AssetRequest* _assetRequest { nullptr }; }; From 9d61de6cd59111b3a026be9d0e534943754a7497 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 14:38:55 -0800 Subject: [PATCH 020/258] add a mapping migration for pre-mapping assets --- assignment-client/src/assets/AssetServer.cpp | 35 ++++++++++++++++++-- assignment-client/src/assets/AssetServer.h | 2 ++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2777496d97..87d6cb9cdf 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -127,7 +127,6 @@ void AssetServer::completeSetup() { qDebug() << "\tCopying from " << from << " to " << to; QFile::copy(from, to); } - } } @@ -141,9 +140,42 @@ void AssetServer::completeSetup() { qInfo() << "There are" << hashedFiles.size() << "asset files in the asset directory."; + performMappingMigration(); + nodeList->addNodeTypeToInterestSet(NodeType::Agent); } +void AssetServer::performMappingMigration() { + QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}(\\.[\\w]+)+$" }; + + auto files = _resourcesDirectory.entryInfoList(QDir::Files); + + for (const auto& fileInfo : files) { + if (hashFileRegex.exactMatch(fileInfo.fileName())) { + // we have a pre-mapping file that we should migrate to the new mapping system + qDebug() << "Migrating pre-mapping file" << fileInfo.fileName(); + + // rename the file to the same name with no extension + QFile oldFile { fileInfo.absoluteFilePath() }; + + auto oldAbsolutePath = fileInfo.absoluteFilePath(); + auto oldFilename = fileInfo.fileName(); + auto fullExtension = oldFilename.mid(oldFilename.indexOf('.')); + + qDebug() << "Moving" << oldAbsolutePath << "to" << oldAbsolutePath.replace(fullExtension, ""); + + bool renamed = oldFile.rename(oldAbsolutePath.replace(fullExtension, "")); + if (!renamed) { + qWarning() << "Could not migrate pre-mapping file" << fileInfo.fileName(); + } else { + qDebug() << "Renamed pre-mapping file" << fileInfo.fileName(); + + // add a new mapping with the old extension and a truncated version of the hash + } + } + } +} + void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; message->readPrimitive(&messageID); @@ -194,7 +226,6 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me nodeList->sendPacket(std::move(replyPacket), *senderNode); } ->>>>>>> db98e46... Update atp mapping operations to use a single packet void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 1eee4feb94..1face3be26 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -55,6 +55,8 @@ private: static void writeError(NLPacketList* packetList, AssetServerError error); + void performMappingMigration(); + Mapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; From 18b22cbd16b9d47e986dee5818d7845e17fa7485 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 14:43:17 -0800 Subject: [PATCH 021/258] add a mapping for pre-mapping migrated files --- assignment-client/src/assets/AssetServer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 87d6cb9cdf..611ff0161c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -171,6 +171,13 @@ void AssetServer::performMappingMigration() { qDebug() << "Renamed pre-mapping file" << fileInfo.fileName(); // add a new mapping with the old extension and a truncated version of the hash + static const int TRUNCATED_HASH_NUM_CHAR = 16; + auto fakeFileName = oldFilename.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; + + auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH); + + qDebug() << "Adding a migration mapping from" << fakeFileName << "to" << hash; + _fileMapping[fakeFileName] = hash; } } } From 82cd8aed8cd1c244c18489ec924065eda88e8643 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 14:46:54 -0800 Subject: [PATCH 022/258] protect mapping clobbering when migrating --- assignment-client/src/assets/AssetServer.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 611ff0161c..c6254aea07 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -150,6 +150,8 @@ void AssetServer::performMappingMigration() { auto files = _resourcesDirectory.entryInfoList(QDir::Files); + bool addedAtLeastOneMapping = false; + for (const auto& fileInfo : files) { if (hashFileRegex.exactMatch(fileInfo.fileName())) { // we have a pre-mapping file that we should migrate to the new mapping system @@ -177,10 +179,23 @@ void AssetServer::performMappingMigration() { auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH); qDebug() << "Adding a migration mapping from" << fakeFileName << "to" << hash; - _fileMapping[fakeFileName] = hash; + + auto it = _fileMapping.find(fakeFileName); + if (it == _fileMapping.end()) { + _fileMapping[fakeFileName] = hash; + + addedAtLeastOneMapping = true; + } else { + qDebug() << "Could not add migration mapping for" << hash << "since a mapping for" << fakeFileName + << "already exists."; + } } } } + + if (addedAtLeastOneMapping) { + // we added at least one new mapping - let's persist changes to file + } } void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { From 5aa287a789416333364fd3fec7f4361a76f75dae Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 15:30:30 -0800 Subject: [PATCH 023/258] handle read/write to asset-server map file --- assignment-client/src/assets/AssetServer.cpp | 137 ++++++++++--------- assignment-client/src/assets/AssetServer.h | 8 +- 2 files changed, 80 insertions(+), 65 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index c6254aea07..e25b56159a 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -12,13 +12,14 @@ #include "AssetServer.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "NetworkLogging.h" #include "NodeType.h" @@ -57,6 +58,8 @@ void AssetServer::run() { ThreadedAssignment::commonInit(ASSET_SERVER_LOGGING_TARGET_NAME, NodeType::AssetServer); } +static const QString ASSET_FILES_SUBDIR = "files"; + void AssetServer::completeSetup() { auto nodeList = DependencyManager::get(); @@ -97,43 +100,18 @@ void AssetServer::completeSetup() { qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); + _resourcesDirectory.mkpath(ASSET_FILES_SUBDIR); - bool noExistingAssets = !_resourcesDirectory.exists() || _resourcesDirectory.entryList(QDir::Files).size() == 0; + _filesDirectory = _resourcesDirectory; + _filesDirectory.cd(ASSET_FILES_SUBDIR); - if (noExistingAssets) { - qDebug() << "Asset resources directory empty, searching for existing asset resources to migrate"; - QString oldDataDirectory = QCoreApplication::applicationDirPath(); - - const QString OLD_RESOURCES_PATH = "assets"; - - auto oldResourcesDirectory = QDir(oldDataDirectory).filePath("resources/" + OLD_RESOURCES_PATH); - - - if (QDir(oldResourcesDirectory).exists()) { - qDebug() << "Existing assets found in " << oldResourcesDirectory << ", copying to " << _resourcesDirectory; - - - QDir resourcesParentDirectory = _resourcesDirectory.filePath(".."); - if (!resourcesParentDirectory.exists()) { - qDebug() << "Creating data directory " << resourcesParentDirectory.absolutePath(); - resourcesParentDirectory.mkpath("."); - } - - auto files = QDir(oldResourcesDirectory).entryList(QDir::Files); - - for (auto& file : files) { - auto from = oldResourcesDirectory + QDir::separator() + file; - auto to = _resourcesDirectory.absoluteFilePath(file); - qDebug() << "\tCopying from " << from << " to " << to; - QFile::copy(from, to); - } - } - } + // load whatever mappings we currently have from the local file + loadMappingFromFile(); - qInfo() << "Serving files from: " << _resourcesDirectory.path(); + qInfo() << "Serving files from: " << _filesDirectory.path(); // Check the asset directory to output some information about what we have - auto files = _resourcesDirectory.entryList(QDir::Files); + auto files = _filesDirectory.entryList(QDir::Files); QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; auto hashedFiles = files.filter(hashFileRegex); @@ -150,8 +128,6 @@ void AssetServer::performMappingMigration() { auto files = _resourcesDirectory.entryInfoList(QDir::Files); - bool addedAtLeastOneMapping = false; - for (const auto& fileInfo : files) { if (hashFileRegex.exactMatch(fileInfo.fileName())) { // we have a pre-mapping file that we should migrate to the new mapping system @@ -162,40 +138,40 @@ void AssetServer::performMappingMigration() { auto oldAbsolutePath = fileInfo.absoluteFilePath(); auto oldFilename = fileInfo.fileName(); + auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH); auto fullExtension = oldFilename.mid(oldFilename.indexOf('.')); - qDebug() << "Moving" << oldAbsolutePath << "to" << oldAbsolutePath.replace(fullExtension, ""); + qDebug() << "\tMoving" << oldAbsolutePath << "to" << oldAbsolutePath.replace(fullExtension, ""); - bool renamed = oldFile.rename(oldAbsolutePath.replace(fullExtension, "")); + bool renamed = oldFile.copy(_filesDirectory.filePath(hash)); if (!renamed) { - qWarning() << "Could not migrate pre-mapping file" << fileInfo.fileName(); + qWarning() << "\tCould not migrate pre-mapping file" << fileInfo.fileName(); } else { - qDebug() << "Renamed pre-mapping file" << fileInfo.fileName(); + qDebug() << "\tRenamed pre-mapping file" << fileInfo.fileName(); // add a new mapping with the old extension and a truncated version of the hash static const int TRUNCATED_HASH_NUM_CHAR = 16; - auto fakeFileName = oldFilename.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; + auto fakeFileName = hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; - auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH); - - qDebug() << "Adding a migration mapping from" << fakeFileName << "to" << hash; + qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash; auto it = _fileMapping.find(fakeFileName); if (it == _fileMapping.end()) { _fileMapping[fakeFileName] = hash; - addedAtLeastOneMapping = true; + + if (writeMappingToFile()) { + // mapping added and persisted, we can remove the migrated file + oldFile.remove(); + qDebug() << "\tMigration completed for" << oldFilename; + } } else { - qDebug() << "Could not add migration mapping for" << hash << "since a mapping for" << fakeFileName + qDebug() << "\tCould not add migration mapping for" << hash << "since a mapping for" << fakeFileName << "already exists."; } } } } - - if (addedAtLeastOneMapping) { - // we added at least one new mapping - let's persist changes to file - } } void AssetServer::handleAssetMappingOperation(QSharedPointer message, SharedNodePointer senderNode) { @@ -214,7 +190,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me auto it = _fileMapping.find(assetPath); if (it != _fileMapping.end()) { - auto assetHash = it->second; + auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket->writePrimitive(AssetServerError::NoError); //replyPacket->write(assetHash.toLatin1().toHex()); @@ -237,7 +213,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me } case AssetMappingOperationType::Delete: { QString assetPath = message->readString(); - bool removed = _fileMapping.erase(assetPath) > 0; + bool removed = _fileMapping.remove(assetPath) > 0; replyPacket->writePrimitive(AssetServerError::NoError); break; @@ -293,7 +269,7 @@ void AssetServer::handleAssetGet(QSharedPointer message, Shared } // Queue task - auto task = new SendAssetTask(message, senderNode, _resourcesDirectory); + auto task = new SendAssetTask(message, senderNode, _filesDirectory); _taskPool.start(task); } @@ -302,7 +278,7 @@ void AssetServer::handleAssetUpload(QSharedPointer message, Sha if (senderNode->getCanRez()) { qDebug() << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); - auto task = new UploadAssetTask(message, senderNode, _resourcesDirectory); + auto task = new UploadAssetTask(message, senderNode, _filesDirectory); _taskPool.start(task); } else { // this is a node the domain told us is not allowed to rez entities @@ -393,14 +369,51 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } +static const QString MAP_FILE_NAME = "map.json"; + void AssetServer::loadMappingFromFile() { + + auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME); + + QFile mapFile { mapFilePath }; + if (mapFile.exists()) { + if (mapFile.open(QIODevice::ReadOnly)) { + auto jsonDocument = QJsonDocument::fromJson(mapFile.readAll()); + _fileMapping = jsonDocument.object().toVariantHash(); + + qInfo() << "Loaded" << _fileMapping.count() << "mappings from map file at" << mapFilePath; + } else { + qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; + setFinished(true); + } + } else { + qInfo() << "No existing mappings loaded from file since no file was found at" << mapFilePath; + } } -void AssetServer::writeMappingToFile() { +bool AssetServer::writeMappingToFile() { + auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME); + + QFile mapFile { mapFilePath }; + if (mapFile.open(QIODevice::WriteOnly)) { + auto jsonObject = QJsonObject::fromVariantHash(_fileMapping); + QJsonDocument jsonDocument { jsonObject }; + + if (mapFile.write(jsonDocument.toJson()) != -1) { + qDebug() << "Wrote JSON mappings to file at" << mapFilePath; + return true; + } else { + qWarning() << "Failed to write JSON mappings to file at" << mapFilePath; + } + } else { + qWarning() << "Failed to open map file at" << mapFilePath; + } + + return false; } AssetHash AssetServer::getMapping(AssetPath path) { - return _fileMapping[path]; + return _fileMapping.value(path).toString(); } void AssetServer::setMapping(AssetPath path, AssetHash hash) { @@ -408,5 +421,5 @@ void AssetServer::setMapping(AssetPath path, AssetHash hash) { } bool AssetServer::deleteMapping(AssetPath path) { - return _fileMapping.erase(path) > 0; + return _fileMapping.remove(path) > 0; } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 1face3be26..f81ca924ed 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,10 +39,11 @@ private slots: void sendStatsPacket(); private: - using Mapping = std::map; + using Mapping = QVariantHash; + // Mapping file operations must be called from main assignment thread only void loadMappingFromFile(); - void writeMappingToFile(); + bool writeMappingToFile(); /// Return the hash mapping for AssetPath `path` AssetHash getMapping(AssetPath path); @@ -57,8 +58,9 @@ private: void performMappingMigration(); - Mapping _fileMapping; + QVariantHash _fileMapping; QDir _resourcesDirectory; + QDir _filesDirectory; QThreadPool _taskPool; }; From 12a774d47f1deaa1909f7219d635a0e3c2243983 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 15:46:44 -0800 Subject: [PATCH 024/258] return error if persistence fails for set/delete operations --- assignment-client/src/assets/AssetServer.cpp | 54 +++++++++++++++++--- assignment-client/src/assets/AssetServer.h | 2 +- libraries/networking/src/AssetUtils.h | 3 +- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index e25b56159a..97c28816b9 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -206,16 +206,25 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me QString assetPath = message->readString(); //auto assetHash = message->read(SHA256_HASH_LENGTH); auto assetHash = message->readString(); - _fileMapping[assetPath] = assetHash; - replyPacket->writePrimitive(AssetServerError::NoError); + if (setMapping(assetPath, assetHash)) { + replyPacket->writePrimitive(AssetServerError::NoError); + } else { + replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + } + + break; } case AssetMappingOperationType::Delete: { QString assetPath = message->readString(); - bool removed = _fileMapping.remove(assetPath) > 0; - replyPacket->writePrimitive(AssetServerError::NoError); + if (deleteMapping(assetPath)) { + replyPacket->writePrimitive(AssetServerError::NoError); + } else { + replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + } + break; } } @@ -416,10 +425,43 @@ AssetHash AssetServer::getMapping(AssetPath path) { return _fileMapping.value(path).toString(); } -void AssetServer::setMapping(AssetPath path, AssetHash hash) { +bool AssetServer::setMapping(AssetPath path, AssetHash hash) { + // remember what the old mapping was in case persistence fails + auto oldMapping = _fileMapping.value(path).toString(); + + // update the in memory QHash _fileMapping[path] = hash; + + // attempt to write to file + if (writeMappingToFile()) { + // persistence succeeded, we are good to go + return true; + } else { + // failed to persist this mapping to file - put back the old one in our in-memory representation + if (oldMapping.isEmpty()) { + _fileMapping.remove(path); + } else { + _fileMapping[path] = oldMapping; + } + + return false; + } } bool AssetServer::deleteMapping(AssetPath path) { - return _fileMapping.remove(path) > 0; + // keep the old mapping in case the delete fails + auto oldMapping = _fileMapping.take(path); + + if (!oldMapping.isNull()) { + // deleted the old mapping, attempt to persist to file + if (writeMappingToFile()) { + // persistence succeeded we are good to go + return true; + } else { + // we didn't delete the previous mapping, put it back in our in-memory representation + _fileMapping[path] = oldMapping.toString(); + } + } + + return false; } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index f81ca924ed..01b3a95ece 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -49,7 +49,7 @@ private: AssetHash getMapping(AssetPath path); /// Set the mapping for path to hash - void setMapping(AssetPath path, AssetHash hash); + bool setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Return `true` if mapping existed, else `false`. bool deleteMapping(AssetPath path); diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index cc9aa60407..e682a48c59 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -32,7 +32,8 @@ enum AssetServerError : uint8_t { AssetNotFound, InvalidByteRange, AssetTooLarge, - PermissionDenied + PermissionDenied, + MappingOperationFailed }; enum AssetMappingOperationType : uint8_t { From 08f181be764e2efa9b30a5afe87052d52869cf64 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Mar 2016 16:30:26 -0800 Subject: [PATCH 025/258] handle mapping requests from AssetResourceRequest --- .../networking/src/AssetResourceRequest.cpp | 57 +++++++++++++++++-- .../networking/src/AssetResourceRequest.h | 4 +- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index c9ac06fca4..d4188467ab 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -15,6 +15,10 @@ #include "AssetUtils.h" AssetResourceRequest::~AssetResourceRequest() { + if (_assetMappingRequest) { + _assetMappingRequest->deleteLater(); + } + if (_assetRequest) { _assetRequest->deleteLater(); } @@ -38,11 +42,9 @@ void AssetResourceRequest::doSend() { // This is an ATP path, we'll need to figure out what the mapping is. // This may incur a roundtrip to the asset-server, or it may return immediately from the cache in AssetClient. - qDebug() << "Detected an asset path! URL is" << _url; + auto path = _url.path(); + requestMappingForPath(path); } else { - - qDebug() << "ATP URL was not an asset path - url is" << _url.toString(); - // We've detected that this is a hash - simply use AssetClient to request that asset auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; @@ -51,6 +53,53 @@ void AssetResourceRequest::doSend() { } } +void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { + auto assetClient = DependencyManager::get(); + _assetMappingRequest = assetClient->createGetMappingRequest(path); + + // if we get a nullptr for createGetMappingRequest assume that there is no currently available asset-server + if (!_assetMappingRequest) { + _result = ServerUnavailable; + _state = Finished; + + emit finished(); + return; + } + + // make sure we'll hear about the result of the get mapping request + connect(_assetMappingRequest, &GetMappingRequest::finished, this, [this, path](GetMappingRequest* request){ + Q_ASSERT(_state == InProgress); + Q_ASSERT(request == _assetMappingRequest); + + switch (request->getError()) { + case AssetServerError::NoError: + // we have no error, we should have a resulting hash - use that to send of a request for that asset + qDebug() << "Got mapping for:" << path << "=>" << request->getHash(); + + requestHash(request->getHash()); + + break; + case AssetServerError::AssetNotFound: + // no result for the mapping request, set error to not found + _result = NotFound; + + // since we've failed we know we are finished + _state = Finished; + emit finished(); + + break; + default: + // these are unexpected errors for a GetMappingRequest object + break; + } + + _assetMappingRequest->deleteLater(); + _assetMappingRequest = nullptr; + }); + + _assetMappingRequest->start(); +} + void AssetResourceRequest::requestHash(const AssetHash& hash) { // in case we haven't parsed a valid hash, return an error now diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index c9a1fbfbf9..2fb8cfd3df 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -31,9 +31,11 @@ private slots: private: bool urlIsAssetPath() const; - + + void requestMappingForPath(const AssetPath& path); void requestHash(const AssetHash& hash); + GetMappingRequest* _assetMappingRequest { nullptr }; AssetRequest* _assetRequest { nullptr }; }; From 37c0417ea607a5131541b13b9e36130450f10f85 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 16:31:49 -0800 Subject: [PATCH 026/258] Add GetAll and Delete mapping requests --- assignment-client/src/assets/AssetServer.cpp | 14 +- assignment-client/src/assets/AssetServer.h | 3 +- libraries/networking/src/AssetClient.cpp | 130 ++++++++++++++++++- libraries/networking/src/AssetClient.h | 48 ++++++- libraries/networking/src/AssetUtils.h | 4 + 5 files changed, 186 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index f685bbe1a9..109ded1b73 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -170,7 +170,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me AssetMappingOperationType operationType; message->readPrimitive(&operationType); - auto replyPacket = NLPacket::create(PacketType::AssetMappingOperationReply); + auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply); replyPacket->writePrimitive(messageID); switch (operationType) { @@ -191,6 +191,16 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me } break; } + case AssetMappingOperationType::GetAll: { + replyPacket->writePrimitive(AssetServerError::NoError); + auto count = _fileMapping.size(); + replyPacket->writePrimitive(count); + for (auto& kv : _fileMapping) { + replyPacket->writeString(kv.first); + replyPacket->writeString(kv.second); + } + break; + } case AssetMappingOperationType::Set: { QString assetPath = message->readString(); //auto assetHash = message->read(SHA256_HASH_LENGTH); @@ -210,7 +220,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me } auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(replyPacket), *senderNode); + nodeList->sendPacketList(std::move(replyPacket), *senderNode); } void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 1eee4feb94..545faa23fb 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,7 +39,6 @@ private slots: void sendStatsPacket(); private: - using Mapping = std::map; void loadMappingFromFile(); void writeMappingToFile(); @@ -55,7 +54,7 @@ private: static void writeError(NLPacketList* packetList, AssetServerError error); - Mapping _fileMapping; + AssetMapping _fileMapping; QDir _resourcesDirectory; QThreadPool _taskPool; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 93139af2d0..6f5e2eee03 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -50,6 +50,34 @@ void GetMappingRequest::start() { emit finished(this); }); }; + +GetAllMappingsRequest::GetAllMappingsRequest() { +}; + +void GetAllMappingsRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->getAllAssetMappings([this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + if (!error) { + size_t numberOfMappings; + message->readPrimitive(&numberOfMappings); + AssetMapping mapping; + for (auto i = 0; i < numberOfMappings; ++i) { + auto path = message->readString(); + auto hash = message->readString(); + mapping[path] = hash; + } + } + emit finished(this); + }); +}; + SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { }; @@ -67,6 +95,23 @@ void SetMappingRequest::start() { }); }; +DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { +}; + +void DeleteMappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + auto assetClient = DependencyManager::get(); + assetClient->deleteAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + // read message + _error = error; + emit finished(this); + }); +}; + AssetClient::AssetClient() { @@ -174,11 +219,18 @@ bool haveAssetServer() { return true; } - GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { return new GetMappingRequest(path); } +GetAllMappingsRequest* AssetClient::createGetAllMappingsRequest() { + return new GetAllMappingsRequest(); +} + +DeleteMappingRequest* AssetClient::createDeleteMappingRequest(const AssetPath& path) { + return new DeleteMappingRequest(path); +} + SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) { return new SetMappingRequest(path, hash); } @@ -404,7 +456,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S } } -bool AssetClient::getAssetMapping(const AssetHash& hash, MappingOperationCallback callback) { +bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -416,7 +468,53 @@ bool AssetClient::getAssetMapping(const AssetHash& hash, MappingOperationCallbac packetList->writePrimitive(AssetMappingOperationType::Get); - packetList->writeString(hash.toUtf8()); + packetList->writeString(path); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + +bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::GetAll); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + } + + return false; +} + +bool AssetClient::deleteAssetMapping(const AssetPath& path, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Delete); + + packetList->writeString(path); nodeList->sendPacketList(std::move(packetList), *assetServer); @@ -440,8 +538,8 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma packetList->writePrimitive(AssetMappingOperationType::Set); - packetList->writeString(path.toUtf8()); - packetList->writeString(hash.toUtf8()); + packetList->writeString(path); + packetList->writeString(hash); nodeList->sendPacketList(std::move(packetList), *assetServer); @@ -653,5 +751,25 @@ void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { request->start(); } -void AssetScriptingInterface::getAllMappings(QString path, QScriptValue callback) { +void AssetScriptingInterface::getAllMappings(QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto map = callback.engine()->newObject(); + + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } + + QScriptValueList args { uint8_t(request->getError()), map }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 0face50367..5e6a071ad8 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -16,6 +16,8 @@ #include #include +#include + #include #include "AssetUtils.h" @@ -61,7 +63,6 @@ private: AssetServerError _error { AssetServerError::NoError }; }; - class SetMappingRequest : public QObject { Q_OBJECT public: @@ -81,6 +82,42 @@ private: AssetServerError _error { AssetServerError::NoError }; }; +class DeleteMappingRequest : public QObject { + Q_OBJECT +public: + DeleteMappingRequest(AssetPath path); + + Q_INVOKABLE void start(); + + AssetServerError getError() { return _error; } + +signals: + void finished(DeleteMappingRequest* thisRequest); + +private: + AssetPath _path; + AssetServerError _error { AssetServerError::NoError }; +}; + +class GetAllMappingsRequest : public QObject { + Q_OBJECT +public: + GetAllMappingsRequest(); + + Q_INVOKABLE void start(); + + AssetServerError getError() { return _error; } + AssetMapping getMappings() { return _mappings; } + +signals: + void finished(GetAllMappingsRequest* thisRequest); + +private: + std::map _mappings; + AssetServerError _error { AssetServerError::NoError }; +}; + + class AssetClient : public QObject, public Dependency { Q_OBJECT @@ -88,6 +125,8 @@ public: AssetClient(); Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); + Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest(); + Q_INVOKABLE DeleteMappingRequest* createDeleteMappingRequest(const AssetPath& path); Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash, const QString& extension); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); @@ -109,8 +148,9 @@ private slots: private: bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool getAllAssetMappings(MappingOperationCallback callback); bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); - bool deleteAssetMapping(const AssetHash& hash, MappingOperationCallback callback); + bool deleteAssetMapping(const AssetPath& path, MappingOperationCallback callback); bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, @@ -131,7 +171,9 @@ private: friend class AssetRequest; friend class AssetUpload; friend class GetMappingRequest; + friend class GetAllMappingsRequest; friend class SetMappingRequest; + friend class DeleteMappingRequest; }; @@ -144,7 +186,7 @@ public: Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); Q_INVOKABLE void getMapping(QString path, QScriptValue callback); - Q_INVOKABLE void getAllMappings(QString path, QScriptValue callback); + Q_INVOKABLE void getAllMappings(QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index f13c9ac729..99e8fdc386 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -14,6 +14,8 @@ #include +#include + #include #include @@ -22,6 +24,7 @@ using DataOffset = int64_t; using AssetPath = QString; using AssetHash = QString; +using AssetMapping = std::map; const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; @@ -37,6 +40,7 @@ enum AssetServerError : uint8_t { enum AssetMappingOperationType : uint8_t { Get = 0, + GetAll, Set, Delete }; From bc99e871e16fa77955760b1cf8b775f99d8073ad Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Mar 2016 16:51:49 -0800 Subject: [PATCH 027/258] Add asset mapping cache --- libraries/networking/src/AssetClient.cpp | 31 +++++++++++++++++++++--- libraries/networking/src/AssetClient.h | 2 ++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 6f5e2eee03..d518961216 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -40,12 +40,13 @@ void GetMappingRequest::start() { } auto assetClient = DependencyManager::get(); - assetClient->getAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; if (!error) { //_hash = message->read(SHA256_HASH_HEX_LENGTH); _hash = message->readString(); + assetClient->_mappingCache[_path] = _hash; } emit finished(this); }); @@ -61,17 +62,19 @@ void GetAllMappingsRequest::start() { } auto assetClient = DependencyManager::get(); - assetClient->getAllAssetMappings([this](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; if (!error) { size_t numberOfMappings; message->readPrimitive(&numberOfMappings); AssetMapping mapping; + assetClient->_mappingCache.clear(); for (auto i = 0; i < numberOfMappings; ++i) { auto path = message->readString(); auto hash = message->readString(); mapping[path] = hash; + assetClient->_mappingCache[path] = hash; } } emit finished(this); @@ -88,9 +91,12 @@ void SetMappingRequest::start() { } auto assetClient = DependencyManager::get(); - assetClient->setAssetMapping(_path, _hash, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; + if (!error) { + assetClient->_mappingCache[_path] = _hash; + } emit finished(this); }); }; @@ -105,9 +111,12 @@ void DeleteMappingRequest::start() { } auto assetClient = DependencyManager::get(); - assetClient->deleteAssetMapping(_path, [this](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; + if (!error) { + assetClient->_mappingCache.remove(_path); + } emit finished(this); }); }; @@ -172,6 +181,8 @@ void AssetClient::clearCache() { return; } + _mappingCache.clear(); + if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; cache->clear(); @@ -650,6 +661,18 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { messageMapIt->second.clear(); } } + + { + auto messageMapIt = _pendingMappingRequests.find(node); + if (messageMapIt != _pendingMappingRequests.end()) { + for (const auto& value : messageMapIt->second) { + value.second(false, AssetServerError::PermissionDenied, QSharedPointer()); + } + messageMapIt->second.clear(); + } + } + + _mappingCache.clear(); } void AssetScriptingInterface::uploadData(QString data, QString extension, QScriptValue callback) { diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 5e6a071ad8..10fad14ee9 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -167,6 +167,8 @@ private: std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; + + QHash _mappingCache; friend class AssetRequest; friend class AssetUpload; From da3e3b7e6c930995257b1a5e156d35a416086f5e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 09:55:48 -0800 Subject: [PATCH 028/258] add handle calls for mapping operations --- assignment-client/src/assets/AssetServer.cpp | 86 ++++++++++++-------- assignment-client/src/assets/AssetServer.h | 5 ++ 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 97c28816b9..2bdef28b89 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -186,45 +186,15 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me switch (operationType) { case AssetMappingOperationType::Get: { - QString assetPath = message->readString(); - - auto it = _fileMapping.find(assetPath); - if (it != _fileMapping.end()) { - auto assetHash = it->toString(); - qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; - replyPacket->writePrimitive(AssetServerError::NoError); - //replyPacket->write(assetHash.toLatin1().toHex()); - replyPacket->writeString(assetHash.toLatin1()); - } - else { - qDebug() << "Mapping not found for: " << assetPath; - replyPacket->writePrimitive(AssetServerError::AssetNotFound); - } + handleGetMappingOperation(*message, senderNode, std::move(replyPacket)); break; } case AssetMappingOperationType::Set: { - QString assetPath = message->readString(); - //auto assetHash = message->read(SHA256_HASH_LENGTH); - auto assetHash = message->readString(); - - if (setMapping(assetPath, assetHash)) { - replyPacket->writePrimitive(AssetServerError::NoError); - } else { - replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); - } - - + handleSetMappingOperation(*message, senderNode, std::move(replyPacket)); break; } case AssetMappingOperationType::Delete: { - QString assetPath = message->readString(); - - if (deleteMapping(assetPath)) { - replyPacket->writePrimitive(AssetServerError::NoError); - } else { - replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); - } - + handleDeleteMappingOperation(*message, senderNode, std::move(replyPacket)); break; } } @@ -233,6 +203,56 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me nodeList->sendPacket(std::move(replyPacket), *senderNode); } +void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, + std::unique_ptr replyPacket) { + QString assetPath = message.readString(); + + auto it = _fileMapping.find(assetPath); + if (it != _fileMapping.end()) { + auto assetHash = it->toString(); + qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; + replyPacket->writePrimitive(AssetServerError::NoError); + //replyPacket->write(assetHash.toLatin1().toHex()); + replyPacket->writeString(assetHash.toLatin1()); + } + else { + qDebug() << "Mapping not found for: " << assetPath; + replyPacket->writePrimitive(AssetServerError::AssetNotFound); + } +} + +void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, + std::unique_ptr replyPacket) { + if (senderNode->getCanRez()) { + QString assetPath = message.readString(); + // auto assetHash = message->read(SHA256_HASH_LENGTH); + auto assetHash = message.readString(); + + if (setMapping(assetPath, assetHash)) { + replyPacket->writePrimitive(AssetServerError::NoError); + } else { + replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + } + } else { + replyPacket->writePrimitive(AssetServerError::PermissionDenied); + } +} + +void AssetServer::handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, + std::unique_ptr replyPacket) { + if (senderNode->getCanRez()) { + QString assetPath = message.readString(); + + if (deleteMapping(assetPath)) { + replyPacket->writePrimitive(AssetServerError::NoError); + } else { + replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + } + } else { + replyPacket->writePrimitive(AssetServerError::PermissionDenied); + } +} + void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 01b3a95ece..a15adc6f60 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -41,6 +41,11 @@ private slots: private: using Mapping = QVariantHash; + void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, std::unique_ptr replyPacket); + void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, std::unique_ptr replyPacket); + void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, + std::unique_ptr replyPacket); + // Mapping file operations must be called from main assignment thread only void loadMappingFromFile(); bool writeMappingToFile(); From fa04f08c4cf31a1beea000218a991a506768402c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 10:01:54 -0800 Subject: [PATCH 029/258] use toHex/fromHex for more compact messaging --- assignment-client/src/assets/AssetServer.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2bdef28b89..dc4e6c90d5 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -212,8 +212,7 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket->writePrimitive(AssetServerError::NoError); - //replyPacket->write(assetHash.toLatin1().toHex()); - replyPacket->writeString(assetHash.toLatin1()); + replyPacket->write(QByteArray::fromHex(assetHash.toLocal8Bit())); } else { qDebug() << "Mapping not found for: " << assetPath; @@ -225,8 +224,7 @@ void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNode std::unique_ptr replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); - // auto assetHash = message->read(SHA256_HASH_LENGTH); - auto assetHash = message.readString(); + auto assetHash = message.read(SHA256_HASH_LENGTH).toHex(); if (setMapping(assetPath, assetHash)) { replyPacket->writePrimitive(AssetServerError::NoError); From bf8a2bc9e5d16a087d3ff18340431bc5b08dbc1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 10:03:29 -0800 Subject: [PATCH 030/258] update read for get mapping to toHex --- libraries/networking/src/AssetClient.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index deb1d9eb7d..78c394cd27 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -44,8 +44,7 @@ void GetMappingRequest::start() { // read message _error = error; if (!error) { - //_hash = message->read(SHA256_HASH_HEX_LENGTH); - _hash = message->readString(); + _hash = message->read(SHA256_HASH_LENGTH).toHex(); } emit finished(this); }); From cf9d4c256ad6db9202db18e67e47de1e1618aaec Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:10:48 -0800 Subject: [PATCH 031/258] Add proper cache checking to GetAssetMapping --- libraries/networking/src/AssetClient.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d518961216..f690c17cbd 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -40,6 +40,15 @@ void GetMappingRequest::start() { } auto assetClient = DependencyManager::get(); + + // Check cache + auto it = assetClient->_mappingCache.constFind(_path); + if (it != assetClient->_mappingCache.constEnd()) { + _hash = it.value(); + emit finished(this); + return; + } + assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { // read message _error = error; From a18486d97db8c13baf11b99d380d44eb575d2873 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:11:37 -0800 Subject: [PATCH 032/258] Fix GetAllMappingsRequest not storing mappings --- libraries/networking/src/AssetClient.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index f690c17cbd..70064c3f69 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -77,12 +77,11 @@ void GetAllMappingsRequest::start() { if (!error) { size_t numberOfMappings; message->readPrimitive(&numberOfMappings); - AssetMapping mapping; assetClient->_mappingCache.clear(); for (auto i = 0; i < numberOfMappings; ++i) { auto path = message->readString(); auto hash = message->readString(); - mapping[path] = hash; + _mappings[path] = hash; assetClient->_mappingCache[path] = hash; } } From 6ca4b72479cf75e35f53c0f064912b5bdc200d6c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:11:57 -0800 Subject: [PATCH 033/258] Add deleteMapping to asset scripting interface --- libraries/networking/src/AssetClient.cpp | 16 ++++++++++++++++ libraries/networking/src/AssetClient.h | 1 + 2 files changed, 17 insertions(+) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 70064c3f69..d8c356aa07 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -782,6 +782,22 @@ void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { request->start(); } +void AssetScriptingInterface::deleteMapping(QString path, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingRequest(path); + + connect(request, &DeleteMappingRequest::finished, this, [this, callback](DeleteMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + void AssetScriptingInterface::getAllMappings(QScriptValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 10fad14ee9..f95f4bc9bc 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -188,6 +188,7 @@ public: Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); Q_INVOKABLE void getMapping(QString path, QScriptValue callback); + Q_INVOKABLE void deleteMapping(QString path, QScriptValue callback); Q_INVOKABLE void getAllMappings(QScriptValue callback); protected: QSet _pendingRequests; From a3533b0b7df4cb93e7bfbc50a295bf607d7348ff Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 10:21:29 -0800 Subject: [PATCH 034/258] repairs for moved packet handling in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 33 +++++++++----------- assignment-client/src/assets/AssetServer.h | 7 ++--- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index dc4e6c90d5..2fbadf56d1 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -186,15 +186,15 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me switch (operationType) { case AssetMappingOperationType::Get: { - handleGetMappingOperation(*message, senderNode, std::move(replyPacket)); + handleGetMappingOperation(*message, senderNode, *replyPacket); break; } case AssetMappingOperationType::Set: { - handleSetMappingOperation(*message, senderNode, std::move(replyPacket)); + handleSetMappingOperation(*message, senderNode, *replyPacket); break; } case AssetMappingOperationType::Delete: { - handleDeleteMappingOperation(*message, senderNode, std::move(replyPacket)); + handleDeleteMappingOperation(*message, senderNode, *replyPacket); break; } } @@ -203,51 +203,48 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me nodeList->sendPacket(std::move(replyPacket), *senderNode); } -void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, - std::unique_ptr replyPacket) { +void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket) { QString assetPath = message.readString(); auto it = _fileMapping.find(assetPath); if (it != _fileMapping.end()) { auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(QByteArray::fromHex(assetHash.toLocal8Bit())); + replyPacket.writePrimitive(AssetServerError::NoError); + replyPacket.write(QByteArray::fromHex(assetHash.toLocal8Bit())); } else { qDebug() << "Mapping not found for: " << assetPath; - replyPacket->writePrimitive(AssetServerError::AssetNotFound); + replyPacket.writePrimitive(AssetServerError::AssetNotFound); } } -void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, - std::unique_ptr replyPacket) { +void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); auto assetHash = message.read(SHA256_HASH_LENGTH).toHex(); if (setMapping(assetPath, assetHash)) { - replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket.writePrimitive(AssetServerError::NoError); } else { - replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + replyPacket.writePrimitive(AssetServerError::MappingOperationFailed); } } else { - replyPacket->writePrimitive(AssetServerError::PermissionDenied); + replyPacket.writePrimitive(AssetServerError::PermissionDenied); } } -void AssetServer::handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, - std::unique_ptr replyPacket) { +void AssetServer::handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); if (deleteMapping(assetPath)) { - replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket.writePrimitive(AssetServerError::NoError); } else { - replyPacket->writePrimitive(AssetServerError::MappingOperationFailed); + replyPacket.writePrimitive(AssetServerError::MappingOperationFailed); } } else { - replyPacket->writePrimitive(AssetServerError::PermissionDenied); + replyPacket.writePrimitive(AssetServerError::PermissionDenied); } } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index a15adc6f60..871898505f 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -41,10 +41,9 @@ private slots: private: using Mapping = QVariantHash; - void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, std::unique_ptr replyPacket); - void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, std::unique_ptr replyPacket); - void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, - std::unique_ptr replyPacket); + void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); + void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); + void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); // Mapping file operations must be called from main assignment thread only void loadMappingFromFile(); From 7db296fa69f3e16143c927416758b10f58725190 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:23:48 -0800 Subject: [PATCH 035/258] Remove unused get/set/deleteMapping in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 12 ------------ assignment-client/src/assets/AssetServer.h | 9 --------- libraries/networking/src/AssetClient.cpp | 1 - 3 files changed, 22 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 109ded1b73..d3198c0f30 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -376,15 +376,3 @@ void AssetServer::loadMappingFromFile() { void AssetServer::writeMappingToFile() { } - -AssetHash AssetServer::getMapping(AssetPath path) { - return _fileMapping[path]; -} - -void AssetServer::setMapping(AssetPath path, AssetHash hash) { - _fileMapping[path] = hash; -} - -bool AssetServer::deleteMapping(AssetPath path) { - return _fileMapping.erase(path) > 0; -} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 545faa23fb..e87c0797c8 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -43,15 +43,6 @@ private: void loadMappingFromFile(); void writeMappingToFile(); - /// Return the hash mapping for AssetPath `path` - AssetHash getMapping(AssetPath path); - - /// Set the mapping for path to hash - void setMapping(AssetPath path, AssetHash hash); - - /// Delete mapping `path`. Return `true` if mapping existed, else `false`. - bool deleteMapping(AssetPath path); - static void writeError(NLPacketList* packetList, AssetServerError error); AssetMapping _fileMapping; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d8c356aa07..27a3acc00b 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -478,7 +478,6 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); - if (assetServer) { auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); From 89b37f78f03f971aa0916b72e9761edf75bdc449 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:26:50 -0800 Subject: [PATCH 036/258] Make AssetServer response reliable and ordered --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index d3198c0f30..b7d02cdb85 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -170,7 +170,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me AssetMappingOperationType operationType; message->readPrimitive(&operationType); - auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply); + auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply, QByteArray(), true, true); replyPacket->writePrimitive(messageID); switch (operationType) { From e3523c86046a6459e78ed0de5350d19ecebfe168 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:28:31 -0800 Subject: [PATCH 037/258] Remove commented out function --- libraries/networking/src/AssetClient.cpp | 28 ------------------------ 1 file changed, 28 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 27a3acc00b..d40aa741a9 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -297,34 +297,6 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex } } -//bool AssetClient::setAssetMapping(const QString& path, MappingOperationCallback callback) { -// auto nodeList = DependencyManager::get(); -// SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); -// -// if (assetServer) { -// auto messageID = ++_currentID; -// -// auto payload = path.toLatin1(); -// auto payloadSize = sizeof(messageID) + payload.size(); -// auto packet = NLPacket::create(PacketType::AssetMappingOperation, payloadSize, true); -// -// qCDebug(asset_client) << "Requesting mapping for" << path << "from asset-server."; -// -// packet->writePrimitive(messageID); -// -// auto bytesWritten = packet->write(payload); -// Q_ASSERT(bytesWritten == payload.size()); -// -// nodeList->sendPacket(std::move(packet), *assetServer); -// -// _pendingMappingRequests[assetServer][messageID] = callback; -// -// return true; -// } -// -// return false; -//} -// bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { From 7bf6b8405ce0fbc5f643f9353a2789c23fa0e0b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 10:27:35 -0800 Subject: [PATCH 038/258] pluralize mappings in AssetServer naming --- assignment-client/src/assets/AssetServer.cpp | 42 ++++++++++---------- assignment-client/src/assets/AssetServer.h | 8 ++-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2fbadf56d1..d4e33c5bf8 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -106,7 +106,7 @@ void AssetServer::completeSetup() { _filesDirectory.cd(ASSET_FILES_SUBDIR); // load whatever mappings we currently have from the local file - loadMappingFromFile(); + loadMappingsFromFile(); qInfo() << "Serving files from: " << _filesDirectory.path(); @@ -155,12 +155,12 @@ void AssetServer::performMappingMigration() { qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash; - auto it = _fileMapping.find(fakeFileName); - if (it == _fileMapping.end()) { - _fileMapping[fakeFileName] = hash; + auto it = _fileMappings.find(fakeFileName); + if (it == _fileMappings.end()) { + _fileMappings[fakeFileName] = hash; - if (writeMappingToFile()) { + if (writeMappingsToFile()) { // mapping added and persisted, we can remove the migrated file oldFile.remove(); qDebug() << "\tMigration completed for" << oldFilename; @@ -206,8 +206,8 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket) { QString assetPath = message.readString(); - auto it = _fileMapping.find(assetPath); - if (it != _fileMapping.end()) { + auto it = _fileMappings.find(assetPath); + if (it != _fileMappings.end()) { auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket.writePrimitive(AssetServerError::NoError); @@ -395,7 +395,7 @@ void AssetServer::sendStatsPacket() { static const QString MAP_FILE_NAME = "map.json"; -void AssetServer::loadMappingFromFile() { +void AssetServer::loadMappingsFromFile() { auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME); @@ -403,9 +403,9 @@ void AssetServer::loadMappingFromFile() { if (mapFile.exists()) { if (mapFile.open(QIODevice::ReadOnly)) { auto jsonDocument = QJsonDocument::fromJson(mapFile.readAll()); - _fileMapping = jsonDocument.object().toVariantHash(); + _fileMappings = jsonDocument.object().toVariantHash(); - qInfo() << "Loaded" << _fileMapping.count() << "mappings from map file at" << mapFilePath; + qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath; } else { qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; setFinished(true); @@ -415,12 +415,12 @@ void AssetServer::loadMappingFromFile() { } } -bool AssetServer::writeMappingToFile() { +bool AssetServer::writeMappingsToFile() { auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME); QFile mapFile { mapFilePath }; if (mapFile.open(QIODevice::WriteOnly)) { - auto jsonObject = QJsonObject::fromVariantHash(_fileMapping); + auto jsonObject = QJsonObject::fromVariantHash(_fileMappings); QJsonDocument jsonDocument { jsonObject }; if (mapFile.write(jsonDocument.toJson()) != -1) { @@ -437,26 +437,26 @@ bool AssetServer::writeMappingToFile() { } AssetHash AssetServer::getMapping(AssetPath path) { - return _fileMapping.value(path).toString(); + return _fileMappings.value(path).toString(); } bool AssetServer::setMapping(AssetPath path, AssetHash hash) { // remember what the old mapping was in case persistence fails - auto oldMapping = _fileMapping.value(path).toString(); + auto oldMapping = _fileMappings.value(path).toString(); // update the in memory QHash - _fileMapping[path] = hash; + _fileMappings[path] = hash; // attempt to write to file - if (writeMappingToFile()) { + if (writeMappingsToFile()) { // persistence succeeded, we are good to go return true; } else { // failed to persist this mapping to file - put back the old one in our in-memory representation if (oldMapping.isEmpty()) { - _fileMapping.remove(path); + _fileMappings.remove(path); } else { - _fileMapping[path] = oldMapping; + _fileMappings[path] = oldMapping; } return false; @@ -465,16 +465,16 @@ bool AssetServer::setMapping(AssetPath path, AssetHash hash) { bool AssetServer::deleteMapping(AssetPath path) { // keep the old mapping in case the delete fails - auto oldMapping = _fileMapping.take(path); + auto oldMapping = _fileMappings.take(path); if (!oldMapping.isNull()) { // deleted the old mapping, attempt to persist to file - if (writeMappingToFile()) { + if (writeMappingsToFile()) { // persistence succeeded we are good to go return true; } else { // we didn't delete the previous mapping, put it back in our in-memory representation - _fileMapping[path] = oldMapping.toString(); + _fileMappings[path] = oldMapping.toString(); } } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 871898505f..b1de4a355a 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -39,15 +39,15 @@ private slots: void sendStatsPacket(); private: - using Mapping = QVariantHash; + using Mappings = QVariantHash; void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacket& replyPacket); // Mapping file operations must be called from main assignment thread only - void loadMappingFromFile(); - bool writeMappingToFile(); + void loadMappingsFromFile(); + bool writeMappingsToFile(); /// Return the hash mapping for AssetPath `path` AssetHash getMapping(AssetPath path); @@ -62,7 +62,7 @@ private: void performMappingMigration(); - QVariantHash _fileMapping; + Mappings _fileMappings; QDir _resourcesDirectory; QDir _filesDirectory; QThreadPool _taskPool; From 0a75a9479014737e72cc7e194d06697dea71196c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:31:40 -0800 Subject: [PATCH 039/258] Remove commented out private slot --- libraries/networking/src/AssetRequest.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 049ab19ef4..3c3459b15d 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -52,9 +52,6 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); -//private slots: - //void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); - private: State _state = NotStarted; Error _error = NoError; From e06c1591fbfb7aa86c7e5dbc7bf114338194a833 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 10:43:26 -0800 Subject: [PATCH 040/258] Remove initializer --- libraries/networking/src/udt/BasePacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index e0b2a8ba3a..dba241f221 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -157,7 +157,7 @@ qint64 BasePacket::writeString(const QString& string) { } QString BasePacket::readString() { - uint32_t size {}; + uint32_t size; readPrimitive(&size); auto string = QString::fromUtf8(getPayload() + pos(), size); seek(pos() + size); From c9bd67bc3e9755add744c1ad0e9c34a5c1ead1cd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 11:18:10 -0800 Subject: [PATCH 041/258] Add MappingRequest superclass and mapping specific errors --- libraries/networking/src/AssetClient.cpp | 90 +++++++++++++++++++----- libraries/networking/src/AssetClient.h | 56 +++++++++------ 2 files changed, 110 insertions(+), 36 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d40aa741a9..b447380e5c 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -30,14 +30,18 @@ MessageID AssetClient::_currentID = 0; -GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { -}; - -void GetMappingRequest::start() { +void MappingRequest::start() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); return; } + doStart(); +}; + +GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { +}; + +void GetMappingRequest::doStart() { auto assetClient = DependencyManager::get(); @@ -50,9 +54,23 @@ void GetMappingRequest::start() { } assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - // read message - _error = error; - if (!error) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::AssetNotFound: + _error = NotFound; + break; + default: + _error = UnknownError; + break; + } + } + + if (!_error) { //_hash = message->read(SHA256_HASH_HEX_LENGTH); _hash = message->readString(); assetClient->_mappingCache[_path] = _hash; @@ -64,7 +82,7 @@ void GetMappingRequest::start() { GetAllMappingsRequest::GetAllMappingsRequest() { }; -void GetAllMappingsRequest::start() { +void GetAllMappingsRequest::doStart() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); return; @@ -72,8 +90,20 @@ void GetAllMappingsRequest::start() { auto assetClient = DependencyManager::get(); assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - // read message - _error = error; + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { size_t numberOfMappings; message->readPrimitive(&numberOfMappings); @@ -92,7 +122,7 @@ void GetAllMappingsRequest::start() { SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { }; -void SetMappingRequest::start() { +void SetMappingRequest::doStart() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); return; @@ -100,8 +130,22 @@ void SetMappingRequest::start() { auto assetClient = DependencyManager::get(); assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - // read message - _error = error; + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + if (!error) { assetClient->_mappingCache[_path] = _hash; } @@ -112,7 +156,7 @@ void SetMappingRequest::start() { DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { }; -void DeleteMappingRequest::start() { +void DeleteMappingRequest::doStart() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); return; @@ -120,8 +164,22 @@ void DeleteMappingRequest::start() { auto assetClient = DependencyManager::get(); assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - // read message - _error = error; + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + if (!error) { assetClient->_mappingCache.remove(_path); } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f95f4bc9bc..b51e7f5316 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -43,78 +43,94 @@ using GetInfoCallback = std::function; using ProgressCallback = std::function; +class MappingRequest : public QObject { + Q_OBJECT +public: + enum Error { + NoError, + NotFound, + NetworkError, + PermissionDenied, + UnknownError + }; -class GetMappingRequest : public QObject { + Q_INVOKABLE void start(); + Error getError() const { return _error; } + +protected: + Error _error { NoError }; + +private: + virtual void doStart() = 0; +}; + + +class GetMappingRequest : public MappingRequest { Q_OBJECT public: GetMappingRequest(AssetPath path); - Q_INVOKABLE void start(); - - AssetHash getHash() { return _hash; } - AssetServerError getError() { return _error; } + AssetHash getHash() const { return _hash; } signals: void finished(GetMappingRequest* thisRequest); private: + virtual void doStart() override; + AssetPath _path; AssetHash _hash; - AssetServerError _error { AssetServerError::NoError }; }; -class SetMappingRequest : public QObject { +class SetMappingRequest : public MappingRequest { Q_OBJECT public: SetMappingRequest(AssetPath path, AssetHash hash); - Q_INVOKABLE void start(); - - AssetHash getHash() { return _hash; } - AssetServerError getError() { return _error; } + AssetHash getHash() const { return _hash; } signals: void finished(SetMappingRequest* thisRequest); private: + virtual void doStart() override; + AssetPath _path; AssetHash _hash; - AssetServerError _error { AssetServerError::NoError }; }; -class DeleteMappingRequest : public QObject { +class DeleteMappingRequest : public MappingRequest { Q_OBJECT public: DeleteMappingRequest(AssetPath path); Q_INVOKABLE void start(); - AssetServerError getError() { return _error; } - signals: void finished(DeleteMappingRequest* thisRequest); private: + virtual void doStart() override; + AssetPath _path; - AssetServerError _error { AssetServerError::NoError }; }; -class GetAllMappingsRequest : public QObject { +class GetAllMappingsRequest : public MappingRequest { Q_OBJECT public: GetAllMappingsRequest(); Q_INVOKABLE void start(); - AssetServerError getError() { return _error; } - AssetMapping getMappings() { return _mappings; } + AssetMapping getMappings() const { return _mappings; } signals: void finished(GetAllMappingsRequest* thisRequest); private: + virtual void doStart() override; + std::map _mappings; - AssetServerError _error { AssetServerError::NoError }; }; From 93d3fb5ccfc983c8c3e154baa3da6ef774ea5688 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 11:19:08 -0800 Subject: [PATCH 042/258] Fix network error response for mapping requests --- libraries/networking/src/AssetClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index b447380e5c..1df9fae192 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -703,7 +703,7 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { auto messageMapIt = _pendingMappingRequests.find(node); if (messageMapIt != _pendingMappingRequests.end()) { for (const auto& value : messageMapIt->second) { - value.second(false, AssetServerError::PermissionDenied, QSharedPointer()); + value.second(false, AssetServerError::NoError, QSharedPointer()); } messageMapIt->second.clear(); } From 5368ae3f9144c1b2cb01c7330eb29433c642e998 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 11:20:15 -0800 Subject: [PATCH 043/258] Remove extraneous thread checks in MappingRequest subclasses --- libraries/networking/src/AssetClient.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 1df9fae192..7631ec5292 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -83,11 +83,6 @@ GetAllMappingsRequest::GetAllMappingsRequest() { }; void GetAllMappingsRequest::doStart() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - auto assetClient = DependencyManager::get(); assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { @@ -123,11 +118,6 @@ SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(pat }; void SetMappingRequest::doStart() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - auto assetClient = DependencyManager::get(); assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { @@ -157,11 +147,6 @@ DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { }; void DeleteMappingRequest::doStart() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - auto assetClient = DependencyManager::get(); assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { From 063826638e8ef963e6b768b87083b726acb28180 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:39:28 -0800 Subject: [PATCH 044/258] move handling of get all operation to sep method --- assignment-client/src/assets/AssetServer.cpp | 21 +++++++++++++------- assignment-client/src/assets/AssetServer.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4ff9715a7d..fadb6fcc13 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -190,13 +190,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me break; } case AssetMappingOperationType::GetAll: { - replyPacket->writePrimitive(AssetServerError::NoError); - auto count = _fileMappings.size(); - replyPacket->writePrimitive(count); - for (auto it = _fileMappings.cbegin(); it != _fileMappings.cend(); ++ it) { - replyPacket->writeString(it.key()); - replyPacket->write(QByteArray::fromHex(it.value().toString().toLocal8Bit())); - } + handleGetAllMappingOperation(*message, senderNode, *replyPacket); break; } case AssetMappingOperationType::Set: { @@ -229,6 +223,19 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode } } +void AssetServer::handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { + replyPacket.writePrimitive(AssetServerError::NoError); + + auto count = _fileMappings.size(); + + replyPacket.writePrimitive(count); + + for (auto it = _fileMappings.cbegin(); it != _fileMappings.cend(); ++ it) { + replyPacket.writeString(it.key()); + replyPacket.write(QByteArray::fromHex(it.value().toString().toUtf8())); + } +} + void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index c4d59a7450..45ec7c6750 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -42,6 +42,7 @@ private: using Mappings = QVariantHash; void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); + void handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); From 4236d8e147ef7ecd05f4c791d380cec03924698e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:40:35 -0800 Subject: [PATCH 045/258] replace toLocal8Bit with toUtf8 for hex conversions --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index fadb6fcc13..2b294fd659 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -215,7 +215,7 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode auto assetHash = it->toString(); qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket.writePrimitive(AssetServerError::NoError); - replyPacket.write(QByteArray::fromHex(assetHash.toLocal8Bit())); + replyPacket.write(QByteArray::fromHex(assetHash.toUtf8())); } else { qDebug() << "Mapping not found for: " << assetPath; From 8107287e6c69551cb894c4ce872fde6525c4a4ba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:42:57 -0800 Subject: [PATCH 046/258] remove start from mapping request subclasses --- libraries/networking/src/AssetClient.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 19544d18e0..cc0eaab035 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -104,8 +104,6 @@ class DeleteMappingRequest : public MappingRequest { public: DeleteMappingRequest(AssetPath path); - Q_INVOKABLE void start(); - signals: void finished(DeleteMappingRequest* thisRequest); @@ -120,8 +118,6 @@ class GetAllMappingsRequest : public MappingRequest { public: GetAllMappingsRequest(); - Q_INVOKABLE void start(); - AssetMapping getMappings() const { return _mappings; } signals: From 7ecfc20dc2000c329db12fa3f05b4a2d12a672f6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:47:11 -0800 Subject: [PATCH 047/258] add error handling for asset-server files directory --- assignment-client/src/assets/AssetServer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2b294fd659..2d6301e2b8 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -100,10 +100,13 @@ void AssetServer::completeSetup() { qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); - _resourcesDirectory.mkpath(ASSET_FILES_SUBDIR); + _filesDirectory = _resourcesDirectory; - _filesDirectory = _resourcesDirectory; - _filesDirectory.cd(ASSET_FILES_SUBDIR); + if (!_resourcesDirectory.mkpath(ASSET_FILES_SUBDIR) || !_filesDirectory.cd(ASSET_FILES_SUBDIR)) { + qCritical() << "Unable to create file directory for asset-server files. Stopping assignment."; + setFinished(true); + return; + } // load whatever mappings we currently have from the local file loadMappingsFromFile(); From 4608eddb401e815f3af6d58270ac271cdf84d437 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:47:55 -0800 Subject: [PATCH 048/258] remove an extra blank line --- assignment-client/src/assets/AssetServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2d6301e2b8..a08bad3212 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -162,7 +162,6 @@ void AssetServer::performMappingMigration() { if (it == _fileMappings.end()) { _fileMappings[fakeFileName] = hash; - if (writeMappingsToFile()) { // mapping added and persisted, we can remove the migrated file oldFile.remove(); From c4845e5ae542caff9163b987f19aec0b69b31a16 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:50:23 -0800 Subject: [PATCH 049/258] remove getMapping call from AssetServer that is unused --- assignment-client/src/assets/AssetServer.cpp | 4 ---- assignment-client/src/assets/AssetServer.h | 3 --- 2 files changed, 7 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index a08bad3212..4768905b25 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -455,10 +455,6 @@ bool AssetServer::writeMappingsToFile() { return false; } -AssetHash AssetServer::getMapping(AssetPath path) { - return _fileMappings.value(path).toString(); -} - bool AssetServer::setMapping(AssetPath path, AssetHash hash) { // remember what the old mapping was in case persistence fails auto oldMapping = _fileMappings.value(path).toString(); diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 45ec7c6750..53a76248d6 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -50,9 +50,6 @@ private: void loadMappingsFromFile(); bool writeMappingsToFile(); - /// Return the hash mapping for AssetPath `path` - AssetHash getMapping(AssetPath path); - /// Set the mapping for path to hash bool setMapping(AssetPath path, AssetHash hash); From 88c1892bf657fce79d2edadefd2e6d6aa8d7f919 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:51:59 -0800 Subject: [PATCH 050/258] remove a comment block re-added in merge --- libraries/networking/src/AssetRequest.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 4c35a46fe7..ac4485a683 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -52,9 +52,6 @@ signals: void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); -//private slots: - //void getAssetCallback(bool responseReceived, AssetServerError serverError, const QByteArray& data); - private: State _state = NotStarted; Error _error = NoError; From e92a9c9741291b2245f7eda1152de0fd89c51c12 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:53:53 -0800 Subject: [PATCH 051/258] fix comment for asset packet version push --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 2c53e01b2a..cbb3374e8c 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -55,7 +55,7 @@ PacketVersion versionForPacketType(PacketType packetType) { return 18; // ICE Server Heartbeat signing case PacketType::AssetGetInfo: case PacketType::AssetGet: - // Introduction of ATP Mappings + // Removal of extension from Asset requests return 18; default: return 17; From 7cc774c5f4f8e2d615e1a13da56a6c944322973f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 11:55:29 -0800 Subject: [PATCH 052/258] indentation fix for _filesDirectory in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4768905b25..c6eb314723 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -100,7 +100,7 @@ void AssetServer::completeSetup() { qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); - _filesDirectory = _resourcesDirectory; + _filesDirectory = _resourcesDirectory; if (!_resourcesDirectory.mkpath(ASSET_FILES_SUBDIR) || !_filesDirectory.cd(ASSET_FILES_SUBDIR)) { qCritical() << "Unable to create file directory for asset-server files. Stopping assignment."; From 1ece9aac2682c5cad73e6a1d80344c928790c184 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 12:08:02 -0800 Subject: [PATCH 053/258] remove extension from asset upload task --- .../src/assets/UploadAssetTask.cpp | 9 ++------- libraries/networking/src/AssetClient.cpp | 17 +++++++---------- libraries/networking/src/AssetClient.h | 6 +++--- libraries/networking/src/AssetUpload.cpp | 14 ++++---------- libraries/networking/src/AssetUpload.h | 4 +--- libraries/networking/src/udt/PacketHeaders.cpp | 1 + .../src/RecordingScriptingInterface.cpp | 4 ++-- 7 files changed, 20 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index 114fd20320..0856a29e1f 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -37,15 +37,10 @@ void UploadAssetTask::run() { MessageID messageID; buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); - uint8_t extensionLength; - buffer.read(reinterpret_cast(&extensionLength), sizeof(extensionLength)); - - QByteArray extension = buffer.read(extensionLength); - uint64_t fileSize; buffer.read(reinterpret_cast(&fileSize), sizeof(fileSize)); - qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes and extension" << extension << "from" + qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes from" << uuidStringWithoutCurlyBraces(_senderNode->getUUID()); auto replyPacket = NLPacket::create(PacketType::AssetUploadReply); @@ -62,7 +57,7 @@ void UploadAssetTask::run() { qDebug() << "Hash for uploaded file from" << uuidStringWithoutCurlyBraces(_senderNode->getUUID()) << "is: (" << hexHash << ") "; - QFile file { _resourcesDir.filePath(QString(hexHash)) + "." + QString(extension) }; + QFile file { _resourcesDir.filePath(QString(hexHash)) }; if (file.exists()) { qDebug() << "[WARNING] This file already exists: " << hexHash; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index b022052409..a443cd3078 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -328,9 +328,9 @@ AssetUpload* AssetClient::createUpload(const QString& filename) { } } -AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& extension) { +AssetUpload* AssetClient::createUpload(const QByteArray& data) { if (haveAssetServer()) { - auto upload = new AssetUpload(data, extension); + auto upload = new AssetUpload(data); upload->moveToThread(thread()); @@ -579,7 +579,7 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma return false; } -bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback) { +bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -589,9 +589,6 @@ bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, auto messageID = ++_currentID; packetList->writePrimitive(messageID); - packetList->writePrimitive(static_cast(extension.length())); - packetList->write(extension.toLatin1().constData(), extension.length()); - uint64_t size = data.length(); packetList->writePrimitive(size); packetList->write(data.constData(), size); @@ -692,17 +689,17 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { _mappingCache.clear(); } -void AssetScriptingInterface::uploadData(QString data, QString extension, QScriptValue callback) { +void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { QByteArray dataByteArray = data.toUtf8(); - auto upload = DependencyManager::get()->createUpload(dataByteArray, extension); + auto upload = DependencyManager::get()->createUpload(dataByteArray); if (!upload) { qCWarning(asset_client) << "Error uploading file to asset server"; return; } - QObject::connect(upload, &AssetUpload::finished, this, [this, callback, extension](AssetUpload* upload, const QString& hash) mutable { + QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { if (callback.isFunction()) { - QString url = "atp://" + hash + "." + extension; + QString url = "atp://" + hash; QScriptValueList args { url }; callback.call(_engine->currentContext()->thisObject(), args); } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index cc0eaab035..44a62f834a 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -140,7 +140,7 @@ public: Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); - Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); + Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data); public slots: void init(); @@ -165,7 +165,7 @@ private: bool getAssetInfo(const QString& hash, GetInfoCallback callback); bool getAsset(const QString& hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback, ProgressCallback progressCallback); - bool uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback); + bool uploadAsset(const QByteArray& data, UploadResultCallback callback); struct GetAssetCallbacks { ReceivedAssetCallback completeCallback; @@ -194,7 +194,7 @@ class AssetScriptingInterface : public QObject { public: AssetScriptingInterface(QScriptEngine* engine); - Q_INVOKABLE void uploadData(QString data, QString extension, QScriptValue callback); + Q_INVOKABLE void uploadData(QString data, QScriptValue callback); Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); Q_INVOKABLE void getMapping(QString path, QScriptValue callback); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 1189c341b1..754d632cce 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -19,9 +19,8 @@ const QString AssetUpload::PERMISSION_DENIED_ERROR = "You do not have permission to upload content to this asset-server."; -AssetUpload::AssetUpload(const QByteArray& data, const QString& extension) : - _data(data), - _extension(extension) +AssetUpload::AssetUpload(const QByteArray& data) : + _data(data) { } @@ -59,12 +58,7 @@ void AssetUpload::start() { // try to open the file at the given filename QFile file { _filename }; - if (file.open(QIODevice::ReadOnly)) { - - // file opened, read the data and grab the extension - _extension = QFileInfo(_filename).suffix(); - _extension = _extension.toLower(); - + if (file.open(QIODevice::ReadOnly)) { _data = file.readAll(); } else { // we couldn't open the file - set the error result @@ -82,7 +76,7 @@ void AssetUpload::start() { qCDebug(asset_client) << "Attempting to upload" << _filename << "to asset-server."; } - assetClient->uploadAsset(_data, _extension, [this](bool responseReceived, AssetServerError error, const QString& hash){ + assetClient->uploadAsset(_data, [this](bool responseReceived, AssetServerError error, const QString& hash){ if (!responseReceived) { _error = NetworkError; } else { diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h index 92f677cbf2..656c1a281e 100644 --- a/libraries/networking/src/AssetUpload.h +++ b/libraries/networking/src/AssetUpload.h @@ -38,12 +38,11 @@ public: static const QString PERMISSION_DENIED_ERROR; AssetUpload(const QString& filename); - AssetUpload(const QByteArray& data, const QString& extension); + AssetUpload(const QByteArray& data); Q_INVOKABLE void start(); const QString& getFilename() const { return _filename; } - const QString& getExtension() const { return _extension; } const Error& getError() const { return _error; } QString getErrorString() const; @@ -54,7 +53,6 @@ signals: private: QString _filename; QByteArray _data; - QString _extension; Error _error; }; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index cbb3374e8c..df1a6f1bec 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -55,6 +55,7 @@ PacketVersion versionForPacketType(PacketType packetType) { return 18; // ICE Server Heartbeat signing case PacketType::AssetGetInfo: case PacketType::AssetGet: + case PacketType::AssetUpload: // Removal of extension from Asset requests return 18; default: diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 25abf2e09e..710f342322 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -198,13 +198,13 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr return false; } - if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip), HFR_EXTENSION)) { + if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip))) { QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { QString clip_atp_url = ""; if (upload->getError() == AssetUpload::NoError) { - clip_atp_url = QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, upload->getExtension()); + clip_atp_url = QString("%1:%2").arg(URL_SCHEME_ATP, hash); upload->deleteLater(); } else { qCWarning(scriptengine) << "Error during the Asset upload."; From 8fa32e75b2c06e08785b6b92cb47fc1b4b787ea2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 12:18:39 -0800 Subject: [PATCH 054/258] client side fixes for upload with no extension --- assignment-client/src/assets/AssetServer.cpp | 18 ++++++++++++------ interface/src/Application.cpp | 6 +++--- interface/src/assets/ATPAssetMigrator.cpp | 2 +- interface/src/ui/AssetUploadDialogFactory.cpp | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index c6eb314723..cbcce9d45e 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -421,14 +421,20 @@ void AssetServer::loadMappingsFromFile() { QFile mapFile { mapFilePath }; if (mapFile.exists()) { if (mapFile.open(QIODevice::ReadOnly)) { - auto jsonDocument = QJsonDocument::fromJson(mapFile.readAll()); - _fileMappings = jsonDocument.object().toVariantHash(); + QJsonParseError error; - qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath; - } else { - qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; - setFinished(true); + auto jsonDocument = QJsonDocument::fromJson(mapFile.readAll(), &error); + + if (error.error == QJsonParseError::NoError) { + _fileMappings = jsonDocument.object().toVariantHash(); + + qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath; + return; + } } + + qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; + setFinished(true); } else { qInfo() << "No existing mappings loaded from file since no file was found at" << mapFilePath; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 660e597752..fdd9a2c008 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4334,14 +4334,14 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) auto filename = QFileInfo(upload->getFilename()).fileName(); if ((upload->getError() == AssetUpload::NoError) && - (FBX_EXTENSION.endsWith(upload->getExtension(), Qt::CaseInsensitive) || - OBJ_EXTENSION.endsWith(upload->getExtension(), Qt::CaseInsensitive))) { + (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || + filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive))) { auto entities = DependencyManager::get(); EntityItemProperties properties; properties.setType(EntityTypes::Model); - properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(upload->getExtension())); + properties.setModelURL(QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash); properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); properties.setName(QUrl(upload->getFilename()).fileName()); diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index dba2047da1..51b2ac558a 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -142,7 +142,7 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { QFileInfo assetInfo { request->getUrl().fileName() }; - auto upload = assetClient->createUpload(request->getData(), assetInfo.completeSuffix()); + auto upload = assetClient->createUpload(request->getData()); if (upload) { // add this URL to our hash of AssetUpload to original URL diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 9cd319815b..46f07cb7df 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -87,7 +87,7 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q // setup the line edit to hold the copiable text QLineEdit* lineEdit = new QLineEdit; - QString atpURL = QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(upload->getExtension()); + QString atpURL = QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash); // set the ATP URL as the text value so it's copiable lineEdit->insert(atpURL); From cf5de317bab54554ae639787eda02c9d420861b1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 12:21:54 -0800 Subject: [PATCH 055/258] use correct error handling for MappingRequest errors --- libraries/networking/src/AssetResourceRequest.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index d4188467ab..fcc4e12456 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -72,14 +72,14 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { Q_ASSERT(request == _assetMappingRequest); switch (request->getError()) { - case AssetServerError::NoError: + case MappingRequest::NoError: // we have no error, we should have a resulting hash - use that to send of a request for that asset qDebug() << "Got mapping for:" << path << "=>" << request->getHash(); requestHash(request->getHash()); break; - case AssetServerError::AssetNotFound: + case MappingRequest::NotFound: // no result for the mapping request, set error to not found _result = NotFound; @@ -90,6 +90,12 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { break; default: // these are unexpected errors for a GetMappingRequest object + _result = Error; + + // since we've failed we know we are finished + _state = Finished; + emit finished(); + break; } From 28af9c51e6f620d875db4a7982fcfb701ede6c3f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 12:22:13 -0800 Subject: [PATCH 056/258] add a missing parenthesis --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fdd9a2c008..c4c94a1ed5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4341,7 +4341,7 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) EntityItemProperties properties; properties.setType(EntityTypes::Model); - properties.setModelURL(QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash); + properties.setModelURL(QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash)); properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); properties.setName(QUrl(upload->getFilename()).fileName()); From 969244927b291e5869ab16d398592ad06f6be15a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 13:09:20 -0800 Subject: [PATCH 057/258] use extension for entity add for drag and drop upload --- interface/src/Application.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c4c94a1ed5..a079c3ccbe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4331,7 +4331,8 @@ bool Application::askToUploadAsset(const QString& filename) { } void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) { - auto filename = QFileInfo(upload->getFilename()).fileName(); + auto fileInfo = QFileInfo(upload->getFilename()); + auto filename = fileInfo.fileName(); if ((upload->getError() == AssetUpload::NoError) && (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || @@ -4341,7 +4342,7 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) EntityItemProperties properties; properties.setType(EntityTypes::Model); - properties.setModelURL(QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash)); + properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(fileInfo.completeSuffix())); properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); properties.setName(QUrl(upload->getFilename()).fileName()); From 784f6699989593829291126e387e6cabd20e16f8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Mar 2016 18:30:25 -0800 Subject: [PATCH 058/258] First draft Assets Manager --- interface/resources/qml/AssetsManager.qml | 167 ++++++++++++++++++++ interface/resources/qml/hifi/MenuOption.qml | 1 + interface/src/Application.cpp | 5 + interface/src/Application.h | 1 + interface/src/Menu.cpp | 6 +- interface/src/Menu.h | 1 + 6 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 interface/resources/qml/AssetsManager.qml diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml new file mode 100644 index 0000000000..ac64bc07c6 --- /dev/null +++ b/interface/resources/qml/AssetsManager.qml @@ -0,0 +1,167 @@ +// +// AssetsManager.qml +// +// Created by Clement on 3/1/16 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs +import Qt.labs.settings 1.0 + +import "styles-uit" +import "controls-uit" as HifiControls +import "windows-uit" + +Window { + id: root + objectName: "AssetsManager" + title: "Assets Server" + resizable: true + destroyOnInvisible: true + x: 40; y: 40 + implicitWidth: 384; implicitHeight: 640 + minSize: Qt.vector2d(200, 300) + + HifiConstants { id: hifi } + + property var scripts: ScriptDiscoveryService; + property var scriptsModel: scripts.scriptsModelFilter + property var runningScriptsModel: ListModel { } + + Settings { + category: "Overlay.AssetManager" + property alias x: root.x + property alias y: root.y + } + + Component.onCompleted: updateRunningScripts() + + function updateRunningScripts() { + var runningScripts = ScriptDiscoveryService.getRunning(); + runningScriptsModel.clear() + for (var i = 0; i < runningScripts.length; ++i) { + runningScriptsModel.append(runningScripts[i]); + } + } + + Column { + width: pane.contentWidth + + HifiControls.StaticSection { + name: "Asset Directory" + + Row { + id: buttonRow + anchors.left: parent.left + anchors.right: parent.right + + HifiControls.Button { + text: "<" + color: hifi.buttons.white + height: 26 + width: 26 + } + + HifiControls.Button { + text: "O" + color: hifi.buttons.white + height: 26 + width: 26 + } + } + + Item { + // Take the browseButton out of the column flow. + id: deleteButtonContainer + anchors.top: buttonRow.top + anchors.right: parent.right + + HifiControls.Button { + id: deleteButton + anchors.right: parent.right + + text: "DELETE SELECTION" + color: hifi.buttons.red + height: 26 + width: 130 + } + } + + HifiControls.Tree { + id: treeView + height: 155 + treeModel: scriptsModel + colorScheme: hifi.colorSchemes.light + anchors.left: parent.left + anchors.right: parent.right + } + } + + HifiControls.StaticSection { + name: "Upload File" + hasSeparator: true + + HifiControls.TextField { + id: fileUrl + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x + + label: "Paste URL or choose file" + colorScheme: hifi.colorSchemes.light + } + + Item { + // Take the chooseButton out of the column flow. + id: chooseButtonContainer + anchors.top: fileUrl.top + anchors.right: parent.right + + HifiControls.Button { + id: chooseButton + anchors.right: parent.right + + text: "Choose" + color: hifi.buttons.white + enabled: true + + width: 100 + } + } + + CheckBox { + id: addToScene + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x + + text: "Add to scene on upload" + checked: false + } + + Item { + // Take the browseButton out of the column flow. + id: uploadButtonContainer + anchors.top: addToScene.top + anchors.right: parent.right + + HifiControls.Button { + id: uploadButton + anchors.right: parent.right + + text: "Upload" + color: hifi.buttons.blue + enabled: true + height: 30 + width: 155 + } + } + } + } +} + diff --git a/interface/resources/qml/hifi/MenuOption.qml b/interface/resources/qml/hifi/MenuOption.qml index 9ebf5adb54..4894834225 100644 --- a/interface/resources/qml/hifi/MenuOption.qml +++ b/interface/resources/qml/hifi/MenuOption.qml @@ -10,6 +10,7 @@ QtObject { readonly property string animDebugDrawPosition: "Debug Draw Position"; readonly property string antialiasing: "Antialiasing"; readonly property string assetMigration: "ATP Asset Migration"; + readonly property string assetsManager = "Assets Manager"; readonly property string atmosphere: "Atmosphere"; readonly property string attachments: "Attachments..."; readonly property string audioNetworkStats: "Audio Network Stats"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a079c3ccbe..59d0b55dee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4453,6 +4453,11 @@ void Application::toggleRunningScriptsWidget() { //} } +void Application::toggleAssetsManagerWidget() { + static const QUrl url("AssetsManager.qml"); + DependencyManager::get()->show(url, "AssetsManager"); +} + void Application::packageModel() { ModelPackager::package(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 3a727db533..de744e73ab 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -242,6 +242,7 @@ public slots: Q_INVOKABLE void loadScriptURLDialog(); void toggleLogDialog(); void toggleRunningScriptsWidget(); + void toggleAssetsManagerWidget(); void handleLocalServerConnection(); void readArgumentsFromLocalSocket(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d605516380..5c04c1ce38 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -99,10 +99,14 @@ Menu::Menu() { redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, redoAction); - // Edit > Running Sccripts + // Edit > Running Scripts addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); + // Edit > Assets Manager + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetsManager, 0, + qApp, SLOT(toggleAssetsManagerWidget())); + // Edit > Open and Run Script from File... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, qApp, SLOT(loadDialog()), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index fb00416af0..d08540973d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -35,6 +35,7 @@ namespace MenuOption { const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; const QString AssetMigration = "ATP Asset Migration"; + const QString AssetsManager = "Assets Manager"; const QString Attachments = "Attachments..."; const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioNoiseReduction = "Audio Noise Reduction"; From 82d6d3ff01e2c9135f93bc14ac4eb8b1794c93b3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Mar 2016 11:32:46 -0800 Subject: [PATCH 059/258] Small fix to buttons color --- .../resources/qml/controls-uit/Button.qml | 37 ++++++++++++++----- .../qml/styles-uit/HifiConstants.qml | 9 ++++- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index 5daec8eb36..fd18bc2a6f 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -16,7 +16,10 @@ import "../styles-uit" Original.Button { id: button + property int color: 0 + property int colorScheme: hifi.colorShemes.light + width: 120 height: 28 @@ -24,27 +27,43 @@ Original.Button { background: Rectangle { radius: hifi.buttons.radius + gradient: Gradient { GradientStop { position: 0.2 - color: enabled - ? (!pressed && button.color != hifi.buttons.black || (!hovered || pressed) && button.color == hifi.buttons.black - ? hifi.buttons.colorStart[button.color] : hifi.buttons.colorFinish[button.color]) - : hifi.buttons.colorStart[hifi.buttons.white] + color: { + if (!enabled) { + hifi.buttons.disabledColorStart[button.colorScheme] + } else if (pressed) { + hifi.buttons.pressedColor[button.color] + } else if (hovered) { + hifi.buttons.hoveredColor[button.color] + } else { + hifi.buttons.colorStart[button.color] + } + } } GradientStop { position: 1.0 - color: enabled - ? ((!hovered || pressed) && button.color != hifi.buttons.black || !pressed && button.color == hifi.buttons.black - ? hifi.buttons.colorFinish[button.color] : hifi.buttons.colorStart[button.color]) - : hifi.buttons.colorFinish[hifi.buttons.white] + color: { + if (!enabled) { + hifi.buttons.disabledColorFinish[button.colorScheme] + } else if (pressed) { + hifi.buttons.pressedColor[button.color] + } else if (hovered) { + hifi.buttons.hoveredColor[button.color] + } else { + hifi.buttons.colorFinish[button.color] + } + } } } } label: RalewayBold { font.capitalization: Font.AllUppercase - color: enabled ? hifi.buttons.textColor[button.color] : hifi.colors.lightGrayText + color: enabled ? hifi.buttons.textColor[button.color] + : hifi.buttons.disabledTextColor[button.colorScheme] size: hifi.fontSizes.buttonLabel verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 108cf8a221..5f77052c63 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -159,8 +159,13 @@ Item { readonly property int red: 2 readonly property int black: 3 readonly property var textColor: [ colors.darkGray, colors.white, colors.white, colors.white ] - readonly property var colorStart: [ "#ffffff", "#00b4ef", "#d42043", "#343434" ] - readonly property var colorFinish: [ "#afafaf", "#1080b8", "#94132e", "#000000" ] + readonly property var colorStart: [ colors.white, colors.primaryHighlight, "#d42043", "#343434" ] + readonly property var colorFinish: [ colors.lightGrayText, colors.blueAccent, "#94132e", colors.black ] + readonly property var hoveredColor: [ colorStart[white], colorStart[blue], colorStart[red], colorFinish[black] ] + readonly property var pressedColor: [ colorFinish[white], colorFinish[blue], colorFinish[red], colorStart[black] ] + readonly property var disabledColorStart: [ colorStart[white], colors.baseGrayHighlight] + readonly property var disabledColorFinish: [ colorFinish[white], colors.baseGrayShadow] + readonly property var disabledTextColor: [ colors.lightGrayText, colors.baseGrayShadow] readonly property int radius: 5 } From 30a6dd86294d05cb7ea3f8696771e47b17d1afac Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Mar 2016 11:33:12 -0800 Subject: [PATCH 060/258] Update StaticSection --- interface/resources/qml/AssetsManager.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml index ac64bc07c6..6f7297fe3b 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetsManager.qml @@ -52,8 +52,9 @@ Window { Column { width: pane.contentWidth - HifiControls.StaticSection { + HifiControls.ContentSection { name: "Asset Directory" + isFirst: true Row { id: buttonRow @@ -102,9 +103,8 @@ Window { } } - HifiControls.StaticSection { + HifiControls.ContentSection { name: "Upload File" - hasSeparator: true HifiControls.TextField { id: fileUrl From 6fecb4e1d180c52e2ab5d444a0d2f00d51db457f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Mar 2016 16:05:31 -0800 Subject: [PATCH 061/258] Window fixup --- interface/resources/qml/AssetsManager.qml | 22 ++++++++++++++----- .../qml/controls-uit/ContentSection.qml | 14 +++++++----- .../resources/qml/controls-uit/TextField.qml | 2 +- .../qml/styles-uit/HifiConstants.qml | 7 ++++++ .../resources/qml/windows-uit/Window.qml | 7 ++++-- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml index 6f7297fe3b..e8bb4e1d9b 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetsManager.qml @@ -27,6 +27,8 @@ Window { implicitWidth: 384; implicitHeight: 640 minSize: Qt.vector2d(200, 300) + colorScheme: hifi.colorSchemes.light + HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; @@ -54,6 +56,8 @@ Window { HifiControls.ContentSection { name: "Asset Directory" + spacing: hifi.dimensions.contentSpacing.y + colorScheme: root.colorScheme isFirst: true Row { @@ -64,6 +68,7 @@ Window { HifiControls.Button { text: "<" color: hifi.buttons.white + colorScheme: root.colorScheme height: 26 width: 26 } @@ -71,6 +76,7 @@ Window { HifiControls.Button { text: "O" color: hifi.buttons.white + colorScheme: root.colorScheme height: 26 width: 26 } @@ -88,6 +94,7 @@ Window { text: "DELETE SELECTION" color: hifi.buttons.red + colorScheme: root.colorScheme height: 26 width: 130 } @@ -97,14 +104,16 @@ Window { id: treeView height: 155 treeModel: scriptsModel - colorScheme: hifi.colorSchemes.light + colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right } } HifiControls.ContentSection { - name: "Upload File" + name: "" + spacing: hifi.dimensions.contentSpacing.y + colorScheme: root.colorScheme HifiControls.TextField { id: fileUrl @@ -112,8 +121,9 @@ Window { anchors.right: parent.right anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x - label: "Paste URL or choose file" - colorScheme: hifi.colorSchemes.light + label: "Upload File" + placeholderText: "Paste URL or choose file" + colorScheme: root.colorScheme } Item { @@ -128,13 +138,14 @@ Window { text: "Choose" color: hifi.buttons.white + colorScheme: root.colorScheme enabled: true width: 100 } } - CheckBox { + HifiControls.CheckBox { id: addToScene anchors.left: parent.left anchors.right: parent.right @@ -156,6 +167,7 @@ Window { text: "Upload" color: hifi.buttons.blue + colorScheme: root.colorScheme enabled: true height: 30 width: 155 diff --git a/interface/resources/qml/controls-uit/ContentSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml index d51ab9cd1b..1a03ee339c 100644 --- a/interface/resources/qml/controls-uit/ContentSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -14,10 +14,12 @@ import QtGraphicalEffects 1.0 import "../styles-uit" Column { - property string name: "Static Section" + property string name: "Content Section" property bool isFirst: false property bool isCollapsible: false // Set at creation. property bool isCollapsed: false + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light spacing: 0 // Defer spacing decisions to individual controls. @@ -60,14 +62,14 @@ Column { id: shadow width: frame.width height: 1 - color: hifi.colors.baseGrayShadow + color: hifi.colors.sectionSeparator1[colorScheme] x: -hifi.dimensions.contentMargin.x } Rectangle { width: frame.width height: 1 - color: hifi.colors.baseGrayHighlight + color: hifi.colors.sectionSeparator2[colorScheme] x: -hifi.dimensions.contentMargin.x anchors.top: shadow.bottom } @@ -104,7 +106,7 @@ Column { y: -2 size: hifi.fontSizes.disclosureButton text: isCollapsed ? hifi.glyphs.disclosureButtonExpand : hifi.glyphs.disclosureButtonCollapse - color: hifi.colors.lightGrayText + color: title.color visible: isCollapsible } @@ -124,8 +126,8 @@ Column { start: Qt.point(0, 0) end: Qt.point(0, 4) gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.darkGray } - GradientStop { position: 1.0; color: hifi.colors.baseGray } // Equivalent of darkGray0 over baseGray background. + GradientStop { position: 0.0; color: hifi.colors.sectionGradiantStart[colorScheme] } + GradientStop { position: 1.0; color: hifi.colors.sectionGradiantFinish[colorScheme] } // Equivalent of darkGray0 over baseGray background. } cached: true } diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index ff1bbe8eb6..b0d657652e 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -38,7 +38,7 @@ TextField { : (textField.focus ? hifi.colors.white : hifi.colors.lightGrayText) background: Rectangle { color: isLightColorScheme - ? (textField.focus ? hifi.colors.white : hifi.colors.lightGray) + ? (textField.focus ? hifi.colors.white : hifi.colors.textFieldLightBackground) : (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow) border.color: hifi.colors.primaryHighlight border.width: textField.focus ? 1 : 0 diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 5f77052c63..577b0a3c51 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -83,6 +83,13 @@ Item { readonly property color dropDownLightFinish: "#afafaf" readonly property color dropDownDarkStart: "#7d7d7d" readonly property color dropDownDarkFinish: "#6b6a6b" + readonly property color textFieldLightBackground: "#d4d4d4" + readonly property color sectionSeparator1: [ baseGrayHighlight, baseGrayShadow] + readonly property color sectionSeparator2: [ white, baseGrayHighlight] + readonly property color sectiongGradiantStart: [ darkGray, darkGray] + readonly property color sectionGradiantFinish: [ darkGray0, darkGray0] + readonly property color backgroundLight: faintGray + readonly property color backgroundDark: baseGray } Item { diff --git a/interface/resources/qml/windows-uit/Window.qml b/interface/resources/qml/windows-uit/Window.qml index 429c6d5dcc..90f973e796 100644 --- a/interface/resources/qml/windows-uit/Window.qml +++ b/interface/resources/qml/windows-uit/Window.qml @@ -52,6 +52,9 @@ Fadable { // property bool pinned: false property bool resizable: false + property int colorScheme: hifi.colorSchemes.dark + readonly property int isLightScheme: colorScheme == hifi.colorSchemes.light + property vector2d minSize: Qt.vector2d(100, 100) property vector2d maxSize: Qt.vector2d(1280, 720) @@ -137,7 +140,7 @@ Fadable { id: contentBackground anchors.fill: parent anchors.rightMargin: parent.isScrolling ? 11 : 0 - color: hifi.colors.baseGray + color: isLightScheme ? hifi.colors.backgroundLight : hifi.colors.backgroundDark visible: modality != Qt.ApplicationModal } @@ -217,7 +220,7 @@ Fadable { } width: parent.contentWidth height: footer.height + 2 * hifi.dimensions.contentSpacing.y - color: hifi.colors.baseGray + color: isLightScheme ? hifi.colors.backgroundLight : hifi.colors.backgroundDark visible: footer.height > 0 Item { From d0e29846f4f40aa9cf34867bbc7bd5e7716a6c10 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Mar 2016 18:01:53 -0800 Subject: [PATCH 062/258] Add GlyphButton --- interface/resources/qml/AssetsManager.qml | 8 +-- .../resources/qml/controls-uit/Button.qml | 34 +++++---- .../qml/controls-uit/GlyphButton.qml | 71 +++++++++++++++++++ .../qml/styles-uit/HifiConstants.qml | 4 ++ 4 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 interface/resources/qml/controls-uit/GlyphButton.qml diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml index e8bb4e1d9b..7b0dfd4cec 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetsManager.qml @@ -65,16 +65,16 @@ Window { anchors.left: parent.left anchors.right: parent.right - HifiControls.Button { - text: "<" + HifiControls.GlyphButton { + glyph: hifi.glyphs.back color: hifi.buttons.white colorScheme: root.colorScheme height: 26 width: 26 } - HifiControls.Button { - text: "O" + HifiControls.GlyphButton { + glyph: hifi.glyphs.reload color: hifi.buttons.white colorScheme: root.colorScheme height: 26 diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index fd18bc2a6f..140abb0a07 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -15,8 +15,6 @@ import QtQuick.Controls.Styles 1.4 import "../styles-uit" Original.Button { - id: button - property int color: 0 property int colorScheme: hifi.colorShemes.light @@ -32,28 +30,28 @@ Original.Button { GradientStop { position: 0.2 color: { - if (!enabled) { - hifi.buttons.disabledColorStart[button.colorScheme] - } else if (pressed) { - hifi.buttons.pressedColor[button.color] - } else if (hovered) { - hifi.buttons.hoveredColor[button.color] + if (!control.enabled) { + hifi.buttons.disabledColorStart[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] } else { - hifi.buttons.colorStart[button.color] + hifi.buttons.colorStart[control.color] } } } GradientStop { position: 1.0 color: { - if (!enabled) { - hifi.buttons.disabledColorFinish[button.colorScheme] - } else if (pressed) { - hifi.buttons.pressedColor[button.color] - } else if (hovered) { - hifi.buttons.hoveredColor[button.color] + if (!control.enabled) { + hifi.buttons.disabledColorFinish[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] } else { - hifi.buttons.colorFinish[button.color] + hifi.buttons.colorFinish[control.color] } } } @@ -62,8 +60,8 @@ Original.Button { label: RalewayBold { font.capitalization: Font.AllUppercase - color: enabled ? hifi.buttons.textColor[button.color] - : hifi.buttons.disabledTextColor[button.colorScheme] + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme] size: hifi.fontSizes.buttonLabel verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter diff --git a/interface/resources/qml/controls-uit/GlyphButton.qml b/interface/resources/qml/controls-uit/GlyphButton.qml new file mode 100644 index 0000000000..c4ee53c04f --- /dev/null +++ b/interface/resources/qml/controls-uit/GlyphButton.qml @@ -0,0 +1,71 @@ +// +// GlyphButton.qml +// +// Created by Clement on 3/7/16 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +import QtQuick 2.5 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 + +import "../styles-uit" + +Original.Button { + property int color: 0 + property int colorScheme: hifi.colorShemes.light + property string glyph: "" + + width: 120 + height: 28 + + style: ButtonStyle { + + background: Rectangle { + radius: hifi.buttons.radius + + gradient: Gradient { + GradientStop { + position: 0.2 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorStart[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] + } else { + hifi.buttons.colorStart[control.color] + } + } + } + GradientStop { + position: 1.0 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorFinish[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] + } else { + hifi.buttons.colorFinish[control.color] + } + } + } + } + } + + label: HiFiGlyphs { + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme] + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.glyph + } + } +} diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 577b0a3c51..a63385c57d 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -157,6 +157,10 @@ Item { readonly property string pinInverted: "z" readonly property string reloadSmall: "a" readonly property string resizeHandle: "A" + readonly property string upload: "j" + readonly property string reload: "a" + readonly property string back: "1" + } Item { From 320bd2b4d48f27c5b69426d85104a79799449bcc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 10:21:55 -0800 Subject: [PATCH 063/258] Reset ContentSection scheme --- .../resources/qml/controls-uit/ContentSection.qml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/controls-uit/ContentSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml index 1a03ee339c..6f106a8347 100644 --- a/interface/resources/qml/controls-uit/ContentSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -18,8 +18,6 @@ Column { property bool isFirst: false property bool isCollapsible: false // Set at creation. property bool isCollapsed: false - property int colorScheme: hifi.colorSchemes.light - readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light spacing: 0 // Defer spacing decisions to individual controls. @@ -62,14 +60,14 @@ Column { id: shadow width: frame.width height: 1 - color: hifi.colors.sectionSeparator1[colorScheme] + color: hifi.colors.baseGrayShadow x: -hifi.dimensions.contentMargin.x } Rectangle { width: frame.width height: 1 - color: hifi.colors.sectionSeparator2[colorScheme] + color: hifi.colors.baseGrayHighlight x: -hifi.dimensions.contentMargin.x anchors.top: shadow.bottom } @@ -106,7 +104,7 @@ Column { y: -2 size: hifi.fontSizes.disclosureButton text: isCollapsed ? hifi.glyphs.disclosureButtonExpand : hifi.glyphs.disclosureButtonCollapse - color: title.color + color: hifi.colors.lightGrayText visible: isCollapsible } @@ -126,8 +124,8 @@ Column { start: Qt.point(0, 0) end: Qt.point(0, 4) gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.sectionGradiantStart[colorScheme] } - GradientStop { position: 1.0; color: hifi.colors.sectionGradiantFinish[colorScheme] } // Equivalent of darkGray0 over baseGray background. + GradientStop { position: 0.0; color: hifi.colors.darkGray } + GradientStop { position: 1.0; color: hifi.colors.baseGray } // Equivalent of darkGray0 over baseGray background. } cached: true } From 51be88d4c35d873e89695161784f2456a9068df2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 10:23:37 -0800 Subject: [PATCH 064/258] Reset Window changes --- interface/resources/qml/windows-uit/Window.qml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/windows-uit/Window.qml b/interface/resources/qml/windows-uit/Window.qml index 90f973e796..429c6d5dcc 100644 --- a/interface/resources/qml/windows-uit/Window.qml +++ b/interface/resources/qml/windows-uit/Window.qml @@ -52,9 +52,6 @@ Fadable { // property bool pinned: false property bool resizable: false - property int colorScheme: hifi.colorSchemes.dark - readonly property int isLightScheme: colorScheme == hifi.colorSchemes.light - property vector2d minSize: Qt.vector2d(100, 100) property vector2d maxSize: Qt.vector2d(1280, 720) @@ -140,7 +137,7 @@ Fadable { id: contentBackground anchors.fill: parent anchors.rightMargin: parent.isScrolling ? 11 : 0 - color: isLightScheme ? hifi.colors.backgroundLight : hifi.colors.backgroundDark + color: hifi.colors.baseGray visible: modality != Qt.ApplicationModal } @@ -220,7 +217,7 @@ Fadable { } width: parent.contentWidth height: footer.height + 2 * hifi.dimensions.contentSpacing.y - color: isLightScheme ? hifi.colors.backgroundLight : hifi.colors.backgroundDark + color: hifi.colors.baseGray visible: footer.height > 0 Item { From e0371929a2baa5d52e334de596f3f32d2f8efdd1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 10:27:18 -0800 Subject: [PATCH 065/258] Remove unused variables --- interface/resources/qml/AssetsManager.qml | 6 ++---- interface/resources/qml/styles-uit/HifiConstants.qml | 6 ------ 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetsManager.qml index 7b0dfd4cec..dd83f7e488 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetsManager.qml @@ -27,7 +27,7 @@ Window { implicitWidth: 384; implicitHeight: 640 minSize: Qt.vector2d(200, 300) - colorScheme: hifi.colorSchemes.light + property int colorScheme: hifi.colorSchemes.dark HifiConstants { id: hifi } @@ -57,13 +57,13 @@ Window { HifiControls.ContentSection { name: "Asset Directory" spacing: hifi.dimensions.contentSpacing.y - colorScheme: root.colorScheme isFirst: true Row { id: buttonRow anchors.left: parent.left anchors.right: parent.right + spacing: hifi.dimensions.contentSpacing.x HifiControls.GlyphButton { glyph: hifi.glyphs.back @@ -113,7 +113,6 @@ Window { HifiControls.ContentSection { name: "" spacing: hifi.dimensions.contentSpacing.y - colorScheme: root.colorScheme HifiControls.TextField { id: fileUrl @@ -176,4 +175,3 @@ Window { } } } - diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index a63385c57d..be8e7d8330 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -84,12 +84,6 @@ Item { readonly property color dropDownDarkStart: "#7d7d7d" readonly property color dropDownDarkFinish: "#6b6a6b" readonly property color textFieldLightBackground: "#d4d4d4" - readonly property color sectionSeparator1: [ baseGrayHighlight, baseGrayShadow] - readonly property color sectionSeparator2: [ white, baseGrayHighlight] - readonly property color sectiongGradiantStart: [ darkGray, darkGray] - readonly property color sectionGradiantFinish: [ darkGray0, darkGray0] - readonly property color backgroundLight: faintGray - readonly property color backgroundDark: baseGray } Item { From ded449072fbbf4ae27efd33a7e3f8cbdbab2e3a9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 10:35:22 -0800 Subject: [PATCH 066/258] Rename window --- .../resources/qml/{AssetsManager.qml => AssetServer.qml} | 6 +++--- interface/resources/qml/hifi/MenuOption.qml | 2 +- interface/src/Application.cpp | 6 +++--- interface/src/Application.h | 2 +- interface/src/Menu.cpp | 6 +++--- interface/src/Menu.h | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) rename interface/resources/qml/{AssetsManager.qml => AssetServer.qml} (98%) diff --git a/interface/resources/qml/AssetsManager.qml b/interface/resources/qml/AssetServer.qml similarity index 98% rename from interface/resources/qml/AssetsManager.qml rename to interface/resources/qml/AssetServer.qml index dd83f7e488..dfa0f7bfbd 100644 --- a/interface/resources/qml/AssetsManager.qml +++ b/interface/resources/qml/AssetServer.qml @@ -1,5 +1,5 @@ // -// AssetsManager.qml +// AssetsServer.qml // // Created by Clement on 3/1/16 // Copyright 2016 High Fidelity, Inc. @@ -19,7 +19,7 @@ import "windows-uit" Window { id: root - objectName: "AssetsManager" + objectName: "AssetsServer" title: "Assets Server" resizable: true destroyOnInvisible: true @@ -36,7 +36,7 @@ Window { property var runningScriptsModel: ListModel { } Settings { - category: "Overlay.AssetManager" + category: "Overlay.AssetServer" property alias x: root.x property alias y: root.y } diff --git a/interface/resources/qml/hifi/MenuOption.qml b/interface/resources/qml/hifi/MenuOption.qml index 4894834225..477197f57e 100644 --- a/interface/resources/qml/hifi/MenuOption.qml +++ b/interface/resources/qml/hifi/MenuOption.qml @@ -10,7 +10,7 @@ QtObject { readonly property string animDebugDrawPosition: "Debug Draw Position"; readonly property string antialiasing: "Antialiasing"; readonly property string assetMigration: "ATP Asset Migration"; - readonly property string assetsManager = "Assets Manager"; + readonly property string assetServer = "Asset Server"; readonly property string atmosphere: "Atmosphere"; readonly property string attachments: "Attachments..."; readonly property string audioNetworkStats: "Audio Network Stats"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 59d0b55dee..85ae8604e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4453,9 +4453,9 @@ void Application::toggleRunningScriptsWidget() { //} } -void Application::toggleAssetsManagerWidget() { - static const QUrl url("AssetsManager.qml"); - DependencyManager::get()->show(url, "AssetsManager"); +void Application::toggleAssetServerWidget() { + static const QUrl url("AssetServer.qml"); + DependencyManager::get()->show(url, "AssetServer"); } void Application::packageModel() { diff --git a/interface/src/Application.h b/interface/src/Application.h index de744e73ab..956eb5a1ea 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -242,7 +242,7 @@ public slots: Q_INVOKABLE void loadScriptURLDialog(); void toggleLogDialog(); void toggleRunningScriptsWidget(); - void toggleAssetsManagerWidget(); + void toggleAssetServerWidget(); void handleLocalServerConnection(); void readArgumentsFromLocalSocket(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5c04c1ce38..e9f45a6b9a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -103,9 +103,9 @@ Menu::Menu() { addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); - // Edit > Assets Manager - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetsManager, 0, - qApp, SLOT(toggleAssetsManagerWidget())); + // Edit > Asset Server + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, + qApp, SLOT(toggleAssetServerWidget())); // Edit > Open and Run Script from File... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d08540973d..c605813753 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -35,7 +35,7 @@ namespace MenuOption { const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; const QString AssetMigration = "ATP Asset Migration"; - const QString AssetsManager = "Assets Manager"; + const QString AssetServer = "Asset Server"; const QString Attachments = "Attachments..."; const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioNoiseReduction = "Audio Noise Reduction"; From e32fd4524c09192134f711f97c6e6e026c6bc6cc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 11:46:02 -0800 Subject: [PATCH 067/258] Start wiring UI --- interface/resources/qml/AssetServer.qml | 35 ++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index dfa0f7bfbd..9920003c90 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,6 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter - property var runningScriptsModel: ListModel { } Settings { category: "Overlay.AssetServer" @@ -41,14 +40,24 @@ Window { property alias y: root.y } - Component.onCompleted: updateRunningScripts() - function updateRunningScripts() { - var runningScripts = ScriptDiscoveryService.getRunning(); - runningScriptsModel.clear() - for (var i = 0; i < runningScripts.length; ++i) { - runningScriptsModel.append(runningScripts[i]); - } + function reload() { + print("reload"); + } + + function goBack() { + print("goBack"); + } + + function uploadFile(fileUrl) { + var shouldAddToScene = addToScene.enabled; + print("uploadFile: " + shouldAddToScene); + + } + + function deleteFile() { + print("deleteFile"); + } Column { @@ -71,6 +80,8 @@ Window { colorScheme: root.colorScheme height: 26 width: 26 + + onClicked: root.goBack() } HifiControls.GlyphButton { @@ -79,6 +90,8 @@ Window { colorScheme: root.colorScheme height: 26 width: 26 + + onClicked: root.reload() } } @@ -97,6 +110,8 @@ Window { colorScheme: root.colorScheme height: 26 width: 130 + + onClicked: root.deleteFile() } } @@ -167,9 +182,11 @@ Window { text: "Upload" color: hifi.buttons.blue colorScheme: root.colorScheme - enabled: true height: 30 width: 155 + + enabled: fileUrl.text != "" + onClicked: root.uploadFile(fileUrl.text) } } } From 74fb1aab559b18493fdb466a8e104cb1b810420a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 13:15:04 -0800 Subject: [PATCH 068/258] Add file dialog --- interface/resources/qml/AssetServer.qml | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 9920003c90..bc41ba7e42 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -16,6 +16,7 @@ import Qt.labs.settings 1.0 import "styles-uit" import "controls-uit" as HifiControls import "windows-uit" +import "dialogs" Window { id: root @@ -38,6 +39,7 @@ Window { category: "Overlay.AssetServer" property alias x: root.x property alias y: root.y + property alias directory: "" } @@ -49,9 +51,8 @@ Window { print("goBack"); } - function uploadFile(fileUrl) { - var shouldAddToScene = addToScene.enabled; - print("uploadFile: " + shouldAddToScene); + function uploadFile(fileUrl, addToScene) { + print("uploadFile: " + fileUrl + " " + addToScene); } @@ -117,7 +118,7 @@ Window { HifiControls.Tree { id: treeView - height: 155 + height: 250 treeModel: scriptsModel colorScheme: root.colorScheme anchors.left: parent.left @@ -129,6 +130,11 @@ Window { name: "" spacing: hifi.dimensions.contentSpacing.y + Component { + id: fileBrowserBuilder; + FileDialog { selectDirectory: true } + } + HifiControls.TextField { id: fileUrl anchors.left: parent.left @@ -156,6 +162,14 @@ Window { enabled: true width: 100 + + onClicked: { + var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) }); + browser.selectedFile.connect(function(url){ + console.log(url); + fileUrl.text = fileDialogHelper.urlToPath(url); + }); + } } } @@ -186,7 +200,7 @@ Window { width: 155 enabled: fileUrl.text != "" - onClicked: root.uploadFile(fileUrl.text) + onClicked: root.uploadFile(fileUrl.text, addToScene.checked) } } } From 0bed46d43a89953182cd5aa4f3a64e556d2b0037 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 13:24:36 -0800 Subject: [PATCH 069/258] Fix typos and file browser directory --- interface/resources/qml/AssetServer.qml | 18 +++++++++++------- .../resources/qml/controls-uit/Button.qml | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index bc41ba7e42..c688e30cef 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -1,5 +1,5 @@ // -// AssetsServer.qml +// AssetServer.qml // // Created by Clement on 3/1/16 // Copyright 2016 High Fidelity, Inc. @@ -20,8 +20,8 @@ import "dialogs" Window { id: root - objectName: "AssetsServer" - title: "Assets Server" + objectName: "AssetServer" + title: "Asset Server" resizable: true destroyOnInvisible: true x: 40; y: 40 @@ -34,12 +34,13 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter + property var currentDirectory: "" Settings { category: "Overlay.AssetServer" property alias x: root.x property alias y: root.y - property alias directory: "" + property alias directory: root.currentDirectory } @@ -97,7 +98,7 @@ Window { } Item { - // Take the browseButton out of the column flow. + // Take the deleteButotn out of the column flow. id: deleteButtonContainer anchors.top: buttonRow.top anchors.right: parent.right @@ -164,7 +165,10 @@ Window { width: 100 onClicked: { - var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) }); + var browser = fileBrowserBuilder.createObject(desktop, { + selectDirectory: true, + folder: fileDialogHelper.pathToUrl(currentDirectory) + }); browser.selectedFile.connect(function(url){ console.log(url); fileUrl.text = fileDialogHelper.urlToPath(url); @@ -184,7 +188,7 @@ Window { } Item { - // Take the browseButton out of the column flow. + // Take the uploadButton out of the column flow. id: uploadButtonContainer anchors.top: addToScene.top anchors.right: parent.right diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index 140abb0a07..e7c8320ae6 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -16,7 +16,7 @@ import "../styles-uit" Original.Button { property int color: 0 - property int colorScheme: hifi.colorShemes.light + property int colorScheme: hifi.colorSchemes.light width: 120 height: 28 From 793d20306db508b6a4e49f61801c25f876e0ced9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:24:03 -0800 Subject: [PATCH 070/258] handle multiple paths for mapping delete operations --- assignment-client/src/assets/AssetServer.cpp | 45 +++++++++++++------- assignment-client/src/assets/AssetServer.h | 6 +-- libraries/networking/src/AssetClient.cpp | 33 ++++++++------ libraries/networking/src/AssetClient.h | 20 ++++----- libraries/networking/src/AssetUtils.h | 1 + 5 files changed, 64 insertions(+), 41 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index cbcce9d45e..52a019aff6 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -200,7 +200,7 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me break; } case AssetMappingOperationType::Delete: { - handleDeleteMappingOperation(*message, senderNode, *replyPacket); + handleDeleteMappingsOperation(*message, senderNode, *replyPacket); break; } } @@ -253,11 +253,18 @@ void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNode } } -void AssetServer::handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { +void AssetServer::handleDeleteMappingsOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { if (senderNode->getCanRez()) { - QString assetPath = message.readString(); + int numberOfDeletedMappings { 0 }; + message.readPrimitive(&numberOfDeletedMappings); - if (deleteMapping(assetPath)) { + QStringList mappingsToDelete; + + for (int i = 0; i < numberOfDeletedMappings; ++i) { + mappingsToDelete << message.readString(); + } + + if (deleteMappings(mappingsToDelete)) { replyPacket.writePrimitive(AssetServerError::NoError); } else { replyPacket.writePrimitive(AssetServerError::MappingOperationFailed); @@ -484,20 +491,28 @@ bool AssetServer::setMapping(AssetPath path, AssetHash hash) { } } -bool AssetServer::deleteMapping(AssetPath path) { - // keep the old mapping in case the delete fails - auto oldMapping = _fileMappings.take(path); +bool AssetServer::deleteMappings(const AssetPathList& paths) { + // take a copy of the current mappings in case persistence of these deletes fails + auto oldMappings = _fileMappings; - if (!oldMapping.isNull()) { - // deleted the old mapping, attempt to persist to file - if (writeMappingsToFile()) { - // persistence succeeded we are good to go - return true; + // enumerate the paths to delete and remove them all + for (auto& path : paths) { + auto oldMapping = _fileMappings.take(path); + if (!oldMapping.isNull()) { + qDebug() << "Deleted a mapping:" << path << "=>" << oldMapping.toString(); } else { - // we didn't delete the previous mapping, put it back in our in-memory representation - _fileMappings[path] = oldMapping.toString(); + qDebug() << "Unable to delete a mapping that was not found:" << path; } } - return false; + // deleted the old mappings, attempt to persist to file + if (writeMappingsToFile()) { + // persistence succeeded we are good to go + return true; + } else { + // we didn't delete the previous mapping, put it back in our in-memory representation + _fileMappings = oldMappings; + + return false; + } } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 53a76248d6..f81fcf46b3 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -44,7 +44,7 @@ private: void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); - void handleDeleteMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); + void handleDeleteMappingsOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); // Mapping file operations must be called from main assignment thread only void loadMappingsFromFile(); @@ -53,8 +53,8 @@ private: /// Set the mapping for path to hash bool setMapping(AssetPath path, AssetHash hash); - /// Delete mapping `path`. Return `true` if mapping existed, else `false`. - bool deleteMapping(AssetPath path); + /// Delete mapping `path`. Returns `true` if deletion of mappings succeeds, else `false`. + bool deleteMappings(const AssetPathList& paths); static void writeError(NLPacketList* packetList, AssetServerError error); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index a443cd3078..8b4ff50d89 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -38,7 +38,7 @@ void MappingRequest::start() { doStart(); }; -GetMappingRequest::GetMappingRequest(AssetPath path) : _path(path) { +GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { }; void GetMappingRequest::doStart() { @@ -113,7 +113,7 @@ void GetAllMappingsRequest::doStart() { }); }; -SetMappingRequest::SetMappingRequest(AssetPath path, AssetHash hash) : _path(path), _hash(hash) { +SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : _path(path), _hash(hash) { }; void SetMappingRequest::doStart() { @@ -142,12 +142,12 @@ void SetMappingRequest::doStart() { }); }; -DeleteMappingRequest::DeleteMappingRequest(AssetPath path) : _path(path) { +DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { }; -void DeleteMappingRequest::doStart() { +void DeleteMappingsRequest::doStart() { auto assetClient = DependencyManager::get(); - assetClient->deleteAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { _error = NetworkError; } else { @@ -165,7 +165,10 @@ void DeleteMappingRequest::doStart() { } if (!error) { - assetClient->_mappingCache.remove(_path); + // enumerate the paths and remove them from the cache + for (auto& path : _paths) { + assetClient->_mappingCache.remove(path); + } } emit finished(this); }); @@ -289,8 +292,8 @@ GetAllMappingsRequest* AssetClient::createGetAllMappingsRequest() { return new GetAllMappingsRequest(); } -DeleteMappingRequest* AssetClient::createDeleteMappingRequest(const AssetPath& path) { - return new DeleteMappingRequest(path); +DeleteMappingsRequest* AssetClient::createDeleteMappingsRequest(const AssetPathList& paths) { + return new DeleteMappingsRequest(paths); } SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) { @@ -530,7 +533,7 @@ bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) { return false; } -bool AssetClient::deleteAssetMapping(const AssetPath& path, MappingOperationCallback callback) { +bool AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -542,7 +545,11 @@ bool AssetClient::deleteAssetMapping(const AssetPath& path, MappingOperationCall packetList->writePrimitive(AssetMappingOperationType::Delete); - packetList->writeString(path); + packetList->writePrimitive(int(paths.size())); + + for (auto& path: paths) { + packetList->writeString(path); + } nodeList->sendPacketList(std::move(packetList), *assetServer); @@ -787,11 +794,11 @@ void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { request->start(); } -void AssetScriptingInterface::deleteMapping(QString path, QScriptValue callback) { +void AssetScriptingInterface::deleteMappings(QStringList paths, QScriptValue callback) { auto assetClient = DependencyManager::get(); - auto request = assetClient->createDeleteMappingRequest(path); + auto request = assetClient->createDeleteMappingsRequest(paths); - connect(request, &DeleteMappingRequest::finished, this, [this, callback](DeleteMappingRequest* request) mutable { + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { QScriptValueList args { uint8_t(request->getError()) }; callback.call(_engine->currentContext()->thisObject(), args); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 44a62f834a..8eba65ecc5 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -68,7 +68,7 @@ private: class GetMappingRequest : public MappingRequest { Q_OBJECT public: - GetMappingRequest(AssetPath path); + GetMappingRequest(const AssetPath& path); AssetHash getHash() const { return _hash; } @@ -85,7 +85,7 @@ private: class SetMappingRequest : public MappingRequest { Q_OBJECT public: - SetMappingRequest(AssetPath path, AssetHash hash); + SetMappingRequest(const AssetPath& path, const AssetHash& hash); AssetHash getHash() const { return _hash; } @@ -99,18 +99,18 @@ private: AssetHash _hash; }; -class DeleteMappingRequest : public MappingRequest { +class DeleteMappingsRequest : public MappingRequest { Q_OBJECT public: - DeleteMappingRequest(AssetPath path); + DeleteMappingsRequest(const AssetPathList& path); signals: - void finished(DeleteMappingRequest* thisRequest); + void finished(DeleteMappingsRequest* thisRequest); private: virtual void doStart() override; - AssetPath _path; + AssetPathList _paths; }; class GetAllMappingsRequest : public MappingRequest { @@ -136,7 +136,7 @@ public: Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest(); - Q_INVOKABLE DeleteMappingRequest* createDeleteMappingRequest(const AssetPath& path); + Q_INVOKABLE DeleteMappingsRequest* createDeleteMappingsRequest(const AssetPathList& paths); Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); @@ -160,7 +160,7 @@ private: bool getAssetMapping(const AssetHash& hash, MappingOperationCallback callback); bool getAllAssetMappings(MappingOperationCallback callback); bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); - bool deleteAssetMapping(const AssetPath& path, MappingOperationCallback callback); + bool deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback); bool getAssetInfo(const QString& hash, GetInfoCallback callback); bool getAsset(const QString& hash, DataOffset start, DataOffset end, @@ -185,7 +185,7 @@ private: friend class GetMappingRequest; friend class GetAllMappingsRequest; friend class SetMappingRequest; - friend class DeleteMappingRequest; + friend class DeleteMappingsRequest; }; @@ -198,7 +198,7 @@ public: Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); Q_INVOKABLE void getMapping(QString path, QScriptValue callback); - Q_INVOKABLE void deleteMapping(QString path, QScriptValue callback); + Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); Q_INVOKABLE void getAllMappings(QScriptValue callback); protected: QSet _pendingRequests; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 08988e4791..8925238b0e 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -25,6 +25,7 @@ using DataOffset = int64_t; using AssetPath = QString; using AssetHash = QString; using AssetMapping = std::map; +using AssetPathList = QStringList; const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; From f9f42a085ac185fa58573fbc2e5baf3e112c1024 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:43:55 -0800 Subject: [PATCH 071/258] add client side handling for mapping rename --- libraries/networking/src/AssetClient.cpp | 88 +++++++++++++++++++++++- libraries/networking/src/AssetClient.h | 19 +++++ libraries/networking/src/AssetUtils.h | 3 +- 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 8b4ff50d89..21e72f56a9 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -174,6 +174,46 @@ void DeleteMappingsRequest::doStart() { }); }; +RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : + _oldPath(oldPath), + _newPath(newPath) +{ + +} + +void RenameMappingRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->renameAssetMapping(_oldPath, _newPath, [this, assetClient](bool responseReceived, + AssetServerError error, + QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { + // take the hash mapped for the old path from the cache + auto hash = assetClient->_mappingCache.take(_oldPath); + if (!hash.isEmpty()) { + // use the hash mapped for the old path for the new path + assetClient->_mappingCache[_newPath] = hash; + } + } + emit finished(this); + }); +} + AssetClient::AssetClient() { @@ -300,6 +340,10 @@ SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, c return new SetMappingRequest(path, hash); } +RenameMappingRequest* AssetClient::createRenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) { + return new RenameMappingRequest(oldPath, newPath); +} + AssetRequest* AssetClient::createRequest(const AssetHash& hash) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; @@ -573,7 +617,7 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma packetList->writePrimitive(AssetMappingOperationType::Set); - packetList->writeString(path.toUtf8()); + packetList->writeString(path); packetList->write(QByteArray::fromHex(hash.toUtf8())); nodeList->sendPacketList(std::move(packetList), *assetServer); @@ -586,6 +630,32 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma return false; } +bool AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true); + + auto messageID = ++_currentID; + packetList->writePrimitive(messageID); + + packetList->writePrimitive(AssetMappingOperationType::Rename); + + packetList->writeString(oldPath); + packetList->writeString(newPath); + + nodeList->sendPacketList(std::move(packetList), *assetServer); + + _pendingMappingRequests[assetServer][messageID] = callback; + + return true; + + } + + return false; +} + bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -832,3 +902,19 @@ void AssetScriptingInterface::getAllMappings(QScriptValue callback) { request->start(); } + +void AssetScriptingInterface::renameMapping(QString oldPath, QString newPath, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createRenameMappingRequest(oldPath, newPath); + + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 8eba65ecc5..58f13d8c1e 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -113,6 +113,21 @@ private: AssetPathList _paths; }; +class RenameMappingRequest : public MappingRequest { + Q_OBJECT +public: + RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath); + +signals: + void finished(RenameMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _oldPath; + AssetPath _newPath; +}; + class GetAllMappingsRequest : public MappingRequest { Q_OBJECT public: @@ -138,6 +153,7 @@ public: Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest(); Q_INVOKABLE DeleteMappingsRequest* createDeleteMappingsRequest(const AssetPathList& paths); Q_INVOKABLE SetMappingRequest* createSetMappingRequest(const AssetPath& path, const AssetHash& hash); + Q_INVOKABLE RenameMappingRequest* createRenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath); Q_INVOKABLE AssetRequest* createRequest(const AssetHash& hash); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data); @@ -161,6 +177,7 @@ private: bool getAllAssetMappings(MappingOperationCallback callback); bool setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback); bool deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback); + bool renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback); bool getAssetInfo(const QString& hash, GetInfoCallback callback); bool getAsset(const QString& hash, DataOffset start, DataOffset end, @@ -186,6 +203,7 @@ private: friend class GetAllMappingsRequest; friend class SetMappingRequest; friend class DeleteMappingsRequest; + friend class RenameMappingRequest; }; @@ -200,6 +218,7 @@ public: Q_INVOKABLE void getMapping(QString path, QScriptValue callback); Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); Q_INVOKABLE void getAllMappings(QScriptValue callback); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 8925238b0e..2495326b67 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -44,7 +44,8 @@ enum AssetMappingOperationType : uint8_t { Get = 0, GetAll, Set, - Delete + Delete, + Rename }; QUrl getATPUrl(const QString& hash); From 181b20f6739eee47b4cddf8bb47ebb8ff9e0dbf4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:46:15 -0800 Subject: [PATCH 072/258] move the AssetScriptInterface to script-engine --- libraries/networking/src/AssetClient.cpp | 153 ---------------- libraries/networking/src/AssetClient.h | 20 -- .../src/AssetScriptingInterface.cpp | 172 ++++++++++++++++++ .../src/AssetScriptingInterface.h | 39 ++++ libraries/script-engine/src/ScriptEngine.h | 4 +- 5 files changed, 213 insertions(+), 175 deletions(-) create mode 100644 libraries/script-engine/src/AssetScriptingInterface.cpp create mode 100644 libraries/script-engine/src/AssetScriptingInterface.h diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 21e72f56a9..9f3358bcda 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -765,156 +765,3 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { _mappingCache.clear(); } - -void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { - QByteArray dataByteArray = data.toUtf8(); - auto upload = DependencyManager::get()->createUpload(dataByteArray); - if (!upload) { - qCWarning(asset_client) << "Error uploading file to asset server"; - return; - } - - QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { - if (callback.isFunction()) { - QString url = "atp://" + hash; - QScriptValueList args { url }; - callback.call(_engine->currentContext()->thisObject(), args); - } - }); - upload->start(); -} - -AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : - _engine(engine) -{ -} - -void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { - const QString ATP_SCHEME { "atp://" }; - - if (!urlString.startsWith(ATP_SCHEME)) { - return; - } - - // Make request to atp - auto path = urlString.right(urlString.length() - ATP_SCHEME.length()); - auto parts = path.split(".", QString::SkipEmptyParts); - auto hash = parts.length() > 0 ? parts[0] : ""; - - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - return; - } - - auto assetClient = DependencyManager::get(); - auto assetRequest = assetClient->createRequest(hash); - - if (!assetRequest) { - return; - } - - _pendingRequests << assetRequest; - - connect(assetRequest, &AssetRequest::finished, this, [this, callback](AssetRequest* request) mutable { - Q_ASSERT(request->getState() == AssetRequest::Finished); - - if (request->getError() == AssetRequest::Error::NoError) { - if (callback.isFunction()) { - QString data = QString::fromUtf8(request->getData()); - QScriptValueList args { data }; - callback.call(_engine->currentContext()->thisObject(), args); - } - } - - request->deleteLater(); - _pendingRequests.remove(request); - }); - - assetRequest->start(); -} - -void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createSetMappingRequest(path, hash); - - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetMappingRequest(path); - - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()), request->getHash() }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::deleteMappings(QStringList paths, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createDeleteMappingsRequest(paths); - - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::getAllMappings(QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetAllMappingsRequest(); - - connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto map = callback.engine()->newObject(); - - for (auto& kv : mappings ) { - map.setProperty(kv.first, kv.second); - } - - QScriptValueList args { uint8_t(request->getError()), map }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::renameMapping(QString oldPath, QString newPath, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 58f13d8c1e..1e9ad2afcd 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -14,7 +14,6 @@ #define hifi_AssetClient_h #include -#include #include @@ -206,23 +205,4 @@ private: friend class RenameMappingRequest; }; - -class AssetScriptingInterface : public QObject { - Q_OBJECT -public: - AssetScriptingInterface(QScriptEngine* engine); - - Q_INVOKABLE void uploadData(QString data, QScriptValue callback); - Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); - Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); - Q_INVOKABLE void getMapping(QString path, QScriptValue callback); - Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); - Q_INVOKABLE void getAllMappings(QScriptValue callback); - Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); -protected: - QSet _pendingRequests; - QScriptEngine* _engine; -}; - - #endif diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp new file mode 100644 index 0000000000..4f539d5021 --- /dev/null +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -0,0 +1,172 @@ +// +// AssetScriptingInterface.cpp +// libraries/script-engine/src +// +// Created by Stephen Birarda on 2016-03-08. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AssetScriptingInterface.h" + +#include + +#include +#include +#include + +AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : + _engine(engine) +{ + +} + +void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { + QByteArray dataByteArray = data.toUtf8(); + auto upload = DependencyManager::get()->createUpload(dataByteArray); + if (!upload) { + qCWarning(asset_client) << "Error uploading file to asset server"; + return; + } + + QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { + if (callback.isFunction()) { + QString url = "atp://" + hash; + QScriptValueList args { url }; + callback.call(_engine->currentContext()->thisObject(), args); + } + }); + upload->start(); +} + +void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { + const QString ATP_SCHEME { "atp://" }; + + if (!urlString.startsWith(ATP_SCHEME)) { + return; + } + + // Make request to atp + auto path = urlString.right(urlString.length() - ATP_SCHEME.length()); + auto parts = path.split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + return; + } + + auto assetClient = DependencyManager::get(); + auto assetRequest = assetClient->createRequest(hash); + + if (!assetRequest) { + return; + } + + _pendingRequests << assetRequest; + + connect(assetRequest, &AssetRequest::finished, this, [this, callback](AssetRequest* request) mutable { + Q_ASSERT(request->getState() == AssetRequest::Finished); + + if (request->getError() == AssetRequest::Error::NoError) { + if (callback.isFunction()) { + QString data = QString::fromUtf8(request->getData()); + QScriptValueList args { data }; + callback.call(_engine->currentContext()->thisObject(), args); + } + } + + request->deleteLater(); + _pendingRequests.remove(request); + }); + + assetRequest->start(); +} + +void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::deleteMappings(QStringList paths, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingsRequest(paths); + + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::getAllMappings(QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto map = callback.engine()->newObject(); + + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } + + QScriptValueList args { uint8_t(request->getError()), map }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetScriptingInterface::renameMapping(QString oldPath, QString newPath, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createRenameMappingRequest(oldPath, newPath); + + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QScriptValueList args { uint8_t(request->getError()) }; + + callback.call(_engine->currentContext()->thisObject(), args); + + request->deleteLater(); + + }); + + request->start(); +} diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h new file mode 100644 index 0000000000..287300cac8 --- /dev/null +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -0,0 +1,39 @@ +// +// AssetScriptingInterface.h +// libraries/script-engine/src +// +// Created by Stephen Birarda on 2016-03-08. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#ifndef hifi_AssetScriptingInterface_h +#define hifi_AssetScriptingInterface_h + +#include +#include + +#include + +class AssetScriptingInterface : public QObject { + Q_OBJECT +public: + AssetScriptingInterface(QScriptEngine* engine); + + Q_INVOKABLE void uploadData(QString data, QScriptValue callback); + Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); + Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); + Q_INVOKABLE void getMapping(QString path, QScriptValue callback); + Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); + Q_INVOKABLE void getAllMappings(QScriptValue callback); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); +protected: + QSet _pendingRequests; + QScriptEngine* _engine; +}; + +#endif // hifi_AssetScriptingInterface_h diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 91d4c3f5a5..8e0d2c2f4a 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -32,6 +31,7 @@ #include "MouseEvent.h" #include "ArrayBufferClass.h" +#include "AssetScriptingInterface.h" #include "AudioScriptingInterface.h" #include "Quat.h" #include "ScriptCache.h" @@ -219,4 +219,4 @@ protected: static std::atomic _stoppingAllScripts; }; -#endif // hifi_ScriptEngine_h \ No newline at end of file +#endif // hifi_ScriptEngine_h From 33cadb36dadbde6963ae81014fd35b6e54f6c4e8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 14:57:22 -0800 Subject: [PATCH 073/258] add server side handling for mapping rename --- assignment-client/src/assets/AssetServer.cpp | 43 +++++++++++++++++++- assignment-client/src/assets/AssetServer.h | 6 ++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 52a019aff6..59b9e9fc47 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -203,6 +203,10 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me handleDeleteMappingsOperation(*message, senderNode, *replyPacket); break; } + case AssetMappingOperationType::Rename: { + handleRenameMappingOperation(*message, senderNode, *replyPacket); + break; + } } auto nodeList = DependencyManager::get(); @@ -274,6 +278,21 @@ void AssetServer::handleDeleteMappingsOperation(ReceivedMessage& message, Shared } } +void AssetServer::handleRenameMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { + if (senderNode->getCanRez()) { + QString oldPath = message.readString(); + QString newPath = message.readString(); + + if (renameMapping(oldPath, newPath)) { + replyPacket.writePrimitive(AssetServerError::NoError); + } else { + replyPacket.writePrimitive(AssetServerError::MappingOperationFailed); + } + } else { + replyPacket.writePrimitive(AssetServerError::PermissionDenied); + } +} + void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; @@ -468,7 +487,7 @@ bool AssetServer::writeMappingsToFile() { return false; } -bool AssetServer::setMapping(AssetPath path, AssetHash hash) { +bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { // remember what the old mapping was in case persistence fails auto oldMapping = _fileMappings.value(path).toString(); @@ -516,3 +535,25 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { return false; } } + +bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { + // take the old hash to remove the old mapping + auto oldMapping = _fileMappings[oldPath].toString(); + + if (!oldMapping.isEmpty()) { + _fileMappings[newPath] = oldMapping; + + if (writeMappingsToFile()) { + // persisted the renamed mapping, return success + return true; + } else { + // we couldn't persist the renamed mapping, rollback and return failure + _fileMappings[oldPath] = oldMapping; + + return false; + } + } else { + // failed to find a mapping that was to be renamed, return failure + return false; + } +} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index f81fcf46b3..f8597c3688 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -45,17 +45,21 @@ private: void handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); void handleDeleteMappingsOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); + void handleRenameMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); // Mapping file operations must be called from main assignment thread only void loadMappingsFromFile(); bool writeMappingsToFile(); /// Set the mapping for path to hash - bool setMapping(AssetPath path, AssetHash hash); + bool setMapping(const AssetPath& path, const AssetHash& hash); /// Delete mapping `path`. Returns `true` if deletion of mappings succeeds, else `false`. bool deleteMappings(const AssetPathList& paths); + /// Rename mapping from `oldPath` to `newPath`. Returns true if successful + bool renameMapping(const AssetPath& oldPath, const AssetPath& newPath); + static void writeError(NLPacketList* packetList, AssetServerError error); void performMappingMigration(); From 8d5111a332e0582a0ca7dcb6bd864118ace8117a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 15:30:21 -0800 Subject: [PATCH 074/258] move MappingRequest and subclasses to separate file --- libraries/networking/src/AssetClient.cpp | 186 +--------------- libraries/networking/src/AssetClient.h | 105 +-------- .../networking/src/AssetResourceRequest.cpp | 1 + libraries/networking/src/MappingRequest.cpp | 202 ++++++++++++++++++ libraries/networking/src/MappingRequest.h | 123 +++++++++++ .../src/AssetScriptingInterface.cpp | 1 + 6 files changed, 331 insertions(+), 287 deletions(-) create mode 100644 libraries/networking/src/MappingRequest.cpp create mode 100644 libraries/networking/src/MappingRequest.h diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 9f3358bcda..7c967e681a 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -22,6 +22,7 @@ #include "AssetRequest.h" #include "AssetUpload.h" #include "AssetUtils.h" +#include "MappingRequest.h" #include "NetworkAccessManager.h" #include "NetworkLogging.h" #include "NodeList.h" @@ -30,191 +31,6 @@ MessageID AssetClient::_currentID = 0; -void MappingRequest::start() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - doStart(); -}; - -GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { -}; - -void GetMappingRequest::doStart() { - - auto assetClient = DependencyManager::get(); - - // Check cache - auto it = assetClient->_mappingCache.constFind(_path); - if (it != assetClient->_mappingCache.constEnd()) { - _hash = it.value(); - emit finished(this); - return; - } - - assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - case AssetServerError::AssetNotFound: - _error = NotFound; - break; - default: - _error = UnknownError; - break; - } - } - - if (!_error) { - _hash = message->read(SHA256_HASH_LENGTH).toHex(); - assetClient->_mappingCache[_path] = _hash; - } - emit finished(this); - }); -}; - -GetAllMappingsRequest::GetAllMappingsRequest() { -}; - -void GetAllMappingsRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - default: - _error = UnknownError; - break; - } - } - - - if (!error) { - int numberOfMappings; - message->readPrimitive(&numberOfMappings); - assetClient->_mappingCache.clear(); - for (auto i = 0; i < numberOfMappings; ++i) { - auto path = message->readString(); - auto hash = message->readString(); - _mappings[path] = hash; - assetClient->_mappingCache[path] = hash; - } - } - emit finished(this); - }); -}; - -SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : _path(path), _hash(hash) { -}; - -void SetMappingRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - case AssetServerError::PermissionDenied: - _error = PermissionDenied; - break; - default: - _error = UnknownError; - break; - } - } - - if (!error) { - assetClient->_mappingCache[_path] = _hash; - } - emit finished(this); - }); -}; - -DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { -}; - -void DeleteMappingsRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - case AssetServerError::PermissionDenied: - _error = PermissionDenied; - break; - default: - _error = UnknownError; - break; - } - } - - if (!error) { - // enumerate the paths and remove them from the cache - for (auto& path : _paths) { - assetClient->_mappingCache.remove(path); - } - } - emit finished(this); - }); -}; - -RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : - _oldPath(oldPath), - _newPath(newPath) -{ - -} - -void RenameMappingRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->renameAssetMapping(_oldPath, _newPath, [this, assetClient](bool responseReceived, - AssetServerError error, - QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - case AssetServerError::PermissionDenied: - _error = PermissionDenied; - break; - default: - _error = UnknownError; - break; - } - } - - if (!error) { - // take the hash mapped for the old path from the cache - auto hash = assetClient->_mappingCache.take(_oldPath); - if (!hash.isEmpty()) { - // use the hash mapped for the old path for the new path - assetClient->_mappingCache[_newPath] = hash; - } - } - emit finished(this); - }); -} - - AssetClient::AssetClient() { setCustomDeleter([](Dependency* dependency){ diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 1e9ad2afcd..87b8646be1 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - #ifndef hifi_AssetClient_h #define hifi_AssetClient_h @@ -28,6 +27,9 @@ class GetMappingRequest; class SetMappingRequest; +class GetAllMappingsRequest; +class DeleteMappingsRequest; +class RenameMappingRequest; class AssetRequest; class AssetUpload; @@ -42,107 +44,6 @@ using GetInfoCallback = std::function; using ProgressCallback = std::function; -class MappingRequest : public QObject { - Q_OBJECT -public: - enum Error { - NoError, - NotFound, - NetworkError, - PermissionDenied, - UnknownError - }; - - Q_INVOKABLE void start(); - Error getError() const { return _error; } - -protected: - Error _error { NoError }; - -private: - virtual void doStart() = 0; -}; - - -class GetMappingRequest : public MappingRequest { - Q_OBJECT -public: - GetMappingRequest(const AssetPath& path); - - AssetHash getHash() const { return _hash; } - -signals: - void finished(GetMappingRequest* thisRequest); - -private: - virtual void doStart() override; - - AssetPath _path; - AssetHash _hash; -}; - -class SetMappingRequest : public MappingRequest { - Q_OBJECT -public: - SetMappingRequest(const AssetPath& path, const AssetHash& hash); - - AssetHash getHash() const { return _hash; } - -signals: - void finished(SetMappingRequest* thisRequest); - -private: - virtual void doStart() override; - - AssetPath _path; - AssetHash _hash; -}; - -class DeleteMappingsRequest : public MappingRequest { - Q_OBJECT -public: - DeleteMappingsRequest(const AssetPathList& path); - -signals: - void finished(DeleteMappingsRequest* thisRequest); - -private: - virtual void doStart() override; - - AssetPathList _paths; -}; - -class RenameMappingRequest : public MappingRequest { - Q_OBJECT -public: - RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath); - -signals: - void finished(RenameMappingRequest* thisRequest); - -private: - virtual void doStart() override; - - AssetPath _oldPath; - AssetPath _newPath; -}; - -class GetAllMappingsRequest : public MappingRequest { - Q_OBJECT -public: - GetAllMappingsRequest(); - - AssetMapping getMappings() const { return _mappings; } - -signals: - void finished(GetAllMappingsRequest* thisRequest); - -private: - virtual void doStart() override; - - std::map _mappings; -}; - class AssetClient : public QObject, public Dependency { Q_OBJECT public: diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index fcc4e12456..a588bfb0d8 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -13,6 +13,7 @@ #include "AssetClient.h" #include "AssetUtils.h" +#include "MappingRequest.h" AssetResourceRequest::~AssetResourceRequest() { if (_assetMappingRequest) { diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp new file mode 100644 index 0000000000..187694e134 --- /dev/null +++ b/libraries/networking/src/MappingRequest.cpp @@ -0,0 +1,202 @@ +// +// MappingRequest.cpp +// libraries/networking/src +// +// Created by Stephen Birarda on 2016-03-08. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MappingRequest.h" + +#include + +#include + +#include "AssetClient.h" + +void MappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + doStart(); +}; + +GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { +}; + +void GetMappingRequest::doStart() { + + auto assetClient = DependencyManager::get(); + + // Check cache + auto it = assetClient->_mappingCache.constFind(_path); + if (it != assetClient->_mappingCache.constEnd()) { + _hash = it.value(); + emit finished(this); + return; + } + + assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::AssetNotFound: + _error = NotFound; + break; + default: + _error = UnknownError; + break; + } + } + + if (!_error) { + _hash = message->read(SHA256_HASH_LENGTH).toHex(); + assetClient->_mappingCache[_path] = _hash; + } + emit finished(this); + }); +}; + +GetAllMappingsRequest::GetAllMappingsRequest() { +}; + +void GetAllMappingsRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + default: + _error = UnknownError; + break; + } + } + + + if (!error) { + int numberOfMappings; + message->readPrimitive(&numberOfMappings); + assetClient->_mappingCache.clear(); + for (auto i = 0; i < numberOfMappings; ++i) { + auto path = message->readString(); + auto hash = message->readString(); + _mappings[path] = hash; + assetClient->_mappingCache[path] = hash; + } + } + emit finished(this); + }); +}; + +SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : _path(path), _hash(hash) { +}; + +void SetMappingRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { + assetClient->_mappingCache[_path] = _hash; + } + emit finished(this); + }); +}; + +DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { +}; + +void DeleteMappingsRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { + // enumerate the paths and remove them from the cache + for (auto& path : _paths) { + assetClient->_mappingCache.remove(path); + } + } + emit finished(this); + }); +}; + +RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : +_oldPath(oldPath), +_newPath(newPath) +{ + +} + +void RenameMappingRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->renameAssetMapping(_oldPath, _newPath, [this, assetClient](bool responseReceived, + AssetServerError error, + QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { + // take the hash mapped for the old path from the cache + auto hash = assetClient->_mappingCache.take(_oldPath); + if (!hash.isEmpty()) { + // use the hash mapped for the old path for the new path + assetClient->_mappingCache[_newPath] = hash; + } + } + emit finished(this); + }); +} diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h new file mode 100644 index 0000000000..b9bd867712 --- /dev/null +++ b/libraries/networking/src/MappingRequest.h @@ -0,0 +1,123 @@ +// +// MappingRequest.h +// libraries/networking/src +// +// Created by Stephen Birarda on 2016-03-08. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#ifndef hifi_MappingRequest_h +#define hifi_MappingRequest_h + +#include + +#include "AssetUtils.h" + +class MappingRequest : public QObject { + Q_OBJECT +public: + enum Error { + NoError, + NotFound, + NetworkError, + PermissionDenied, + UnknownError + }; + + Q_INVOKABLE void start(); + Error getError() const { return _error; } + +protected: + Error _error { NoError }; + +private: + virtual void doStart() = 0; +}; + + +class GetMappingRequest : public MappingRequest { + Q_OBJECT +public: + GetMappingRequest(const AssetPath& path); + + AssetHash getHash() const { return _hash; } + +signals: + void finished(GetMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _path; + AssetHash _hash; +}; + +class SetMappingRequest : public MappingRequest { + Q_OBJECT +public: + SetMappingRequest(const AssetPath& path, const AssetHash& hash); + + AssetHash getHash() const { return _hash; } + +signals: + void finished(SetMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _path; + AssetHash _hash; +}; + +class DeleteMappingsRequest : public MappingRequest { + Q_OBJECT +public: + DeleteMappingsRequest(const AssetPathList& path); + +signals: + void finished(DeleteMappingsRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPathList _paths; +}; + +class RenameMappingRequest : public MappingRequest { + Q_OBJECT +public: + RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath); + +signals: + void finished(RenameMappingRequest* thisRequest); + +private: + virtual void doStart() override; + + AssetPath _oldPath; + AssetPath _newPath; +}; + +class GetAllMappingsRequest : public MappingRequest { + Q_OBJECT +public: + GetAllMappingsRequest(); + + AssetMapping getMappings() const { return _mappings; } + +signals: + void finished(GetAllMappingsRequest* thisRequest); + +private: + virtual void doStart() override; + + std::map _mappings; +}; + + +#endif // hifi_MappingRequest_h diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index 4f539d5021..db29008976 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -15,6 +15,7 @@ #include #include +#include #include AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : From 6abd1c50b27b238169145f04d2daa811a825adbd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Mar 2016 15:45:13 -0800 Subject: [PATCH 075/258] remove the inlined writeError in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 3 ++- assignment-client/src/assets/AssetServer.h | 10 ++-------- assignment-client/src/assets/SendAssetTask.cpp | 6 +++--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 59b9e9fc47..13257967ac 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -21,11 +21,12 @@ #include #include +#include + #include "NetworkLogging.h" #include "NodeType.h" #include "SendAssetTask.h" #include "UploadAssetTask.h" -#include const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index f8597c3688..094ea58d41 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -12,10 +12,10 @@ #ifndef hifi_AssetServer_h #define hifi_AssetServer_h -#include +#include +#include #include -#include #include "AssetUtils.h" #include "ReceivedMessage.h" @@ -60,8 +60,6 @@ private: /// Rename mapping from `oldPath` to `newPath`. Returns true if successful bool renameMapping(const AssetPath& oldPath, const AssetPath& newPath); - static void writeError(NLPacketList* packetList, AssetServerError error); - void performMappingMigration(); Mappings _fileMappings; @@ -71,8 +69,4 @@ private: QThreadPool _taskPool; }; -inline void writeError(NLPacketList* packetList, AssetServerError error) { - packetList->writePrimitive(error); -} - #endif diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 33e1ab0fb8..d2b3c6c256 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -56,7 +56,7 @@ void SendAssetTask::run() { replyPacketList->writePrimitive(messageID); if (end <= start) { - writeError(replyPacketList.get(), AssetServerError::InvalidByteRange); + replyPacketList->writePrimitive(AssetServerError::InvalidByteRange); } else { QString filePath = _resourcesDir.filePath(QString(hexHash)); @@ -64,7 +64,7 @@ void SendAssetTask::run() { if (file.open(QIODevice::ReadOnly)) { if (file.size() < end) { - writeError(replyPacketList.get(), AssetServerError::InvalidByteRange); + replyPacketList->writePrimitive(AssetServerError::InvalidByteRange); qCDebug(networking) << "Bad byte range: " << hexHash << " " << start << ":" << end; } else { auto size = end - start; @@ -77,7 +77,7 @@ void SendAssetTask::run() { file.close(); } else { qCDebug(networking) << "Asset not found: " << filePath << "(" << hexHash << ")"; - writeError(replyPacketList.get(), AssetServerError::AssetNotFound); + replyPacketList->writePrimitive(AssetServerError::AssetNotFound); } } From 254e04c4b7dd5d97c92364f68185ef5e4bbf2b59 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 16:09:42 -0800 Subject: [PATCH 076/258] UI change --- interface/resources/qml/AssetServer.qml | 70 ++++++++++++++----------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c688e30cef..e260b5e8d7 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -43,29 +43,36 @@ Window { property alias directory: root.currentDirectory } - function reload() { print("reload"); } - - function goBack() { - print("goBack"); + function addToWorld() { + print("addToWorld"); } - - function uploadFile(fileUrl, addToScene) { - print("uploadFile: " + fileUrl + " " + addToScene); - + function renameFile() { + print("renameFile"); } - function deleteFile() { print("deleteFile"); } + function uploadFile(fileUrl, addToScene) { + var object = desktop.inputDialog({ + label: "Enter asset path", + //placeholderText: "atp:/myFolder/myFile.ext" + }); + object.selected.connect(function(value) { + print(value); + }); + print("uploadFile: " + fileUrl + " " + addToScene); + } + Column { width: pane.contentWidth HifiControls.ContentSection { + id: assetDirectory name: "Asset Directory" spacing: hifi.dimensions.contentSpacing.y isFirst: true @@ -76,16 +83,6 @@ Window { anchors.right: parent.right spacing: hifi.dimensions.contentSpacing.x - HifiControls.GlyphButton { - glyph: hifi.glyphs.back - color: hifi.buttons.white - colorScheme: root.colorScheme - height: 26 - width: 26 - - onClicked: root.goBack() - } - HifiControls.GlyphButton { glyph: hifi.glyphs.reload color: hifi.buttons.white @@ -95,23 +92,35 @@ Window { onClicked: root.reload() } - } - Item { - // Take the deleteButotn out of the column flow. - id: deleteButtonContainer - anchors.top: buttonRow.top - anchors.right: parent.right + HifiControls.Button { + text: "ADD TO WORLD" + color: hifi.buttons.white + colorScheme: root.colorScheme + height: 26 + width: 120 + + onClicked: root.addToWorld() + } + + HifiControls.Button { + text: "RENAME" + color: hifi.buttons.white + colorScheme: root.colorScheme + height: 26 + width: 80 + + onClicked: root.renameFile() + } HifiControls.Button { id: deleteButton - anchors.right: parent.right - text: "DELETE SELECTION" + text: "DELETE" color: hifi.buttons.red colorScheme: root.colorScheme height: 26 - width: 130 + width: 80 onClicked: root.deleteFile() } @@ -119,7 +128,7 @@ Window { HifiControls.Tree { id: treeView - height: 250 + height: 400 treeModel: scriptsModel colorScheme: root.colorScheme anchors.left: parent.left @@ -128,6 +137,7 @@ Window { } HifiControls.ContentSection { + id: uploadSection name: "" spacing: hifi.dimensions.contentSpacing.y @@ -166,7 +176,7 @@ Window { onClicked: { var browser = fileBrowserBuilder.createObject(desktop, { - selectDirectory: true, + selectDirectory: false, folder: fileDialogHelper.pathToUrl(currentDirectory) }); browser.selectedFile.connect(function(url){ From 028c7ab6baacc7ceeb21850988c5b217d415e4ab Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 16:40:54 -0800 Subject: [PATCH 077/258] Add text box --- interface/resources/qml/AssetServer.qml | 57 +++++++++++-------- .../resources/qml/dialogs/QueryDialog.qml | 1 + 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index e260b5e8d7..49c7bd4363 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -34,7 +34,7 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter - property var currentDirectory: "" + property var currentDirectory; Settings { category: "Overlay.AssetServer" @@ -57,15 +57,35 @@ Window { } - function uploadFile(fileUrl, addToScene) { + function chooseClicked() { + var browser = fileBrowserBuilder.createObject(desktop, { + selectDirectory: false, + folder: fileDialogHelper.pathToUrl(currentDirectory) + }); + browser.selectedFile.connect(function(url){ + console.log(url); + fileUrlTextField.text = fileDialogHelper.urlToPath(url); + }); + + } + + function uploadClicked() { + var fileUrl = fileUrlTextField.text + var addToScene = addToSceneCheckBox.checked + var object = desktop.inputDialog({ - label: "Enter asset path", - //placeholderText: "atp:/myFolder/myFile.ext" + label: "Enter asset path:", + prefilledText: "atp:/myFolder/myFile.ext", + placeholderText: "Enter path here" }); - object.selected.connect(function(value) { - print(value); + object.selected.connect(function(destinationPath) { + console.log("Uploading " + fileUrl + " to " + destinationPath + " (addToScene: " + addToScene + ")"); + + + + + }); - print("uploadFile: " + fileUrl + " " + addToScene); } Column { @@ -147,7 +167,7 @@ Window { } HifiControls.TextField { - id: fileUrl + id: fileUrlTextField anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x @@ -160,7 +180,7 @@ Window { Item { // Take the chooseButton out of the column flow. id: chooseButtonContainer - anchors.top: fileUrl.top + anchors.top: fileUrlTextField.top anchors.right: parent.right HifiControls.Button { @@ -174,21 +194,12 @@ Window { width: 100 - onClicked: { - var browser = fileBrowserBuilder.createObject(desktop, { - selectDirectory: false, - folder: fileDialogHelper.pathToUrl(currentDirectory) - }); - browser.selectedFile.connect(function(url){ - console.log(url); - fileUrl.text = fileDialogHelper.urlToPath(url); - }); - } + onClicked: root.chooseClicked() } } HifiControls.CheckBox { - id: addToScene + id: addToSceneCheckBox anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x @@ -200,7 +211,7 @@ Window { Item { // Take the uploadButton out of the column flow. id: uploadButtonContainer - anchors.top: addToScene.top + anchors.top: addToSceneCheckBox.top anchors.right: parent.right HifiControls.Button { @@ -213,8 +224,8 @@ Window { height: 30 width: 155 - enabled: fileUrl.text != "" - onClicked: root.uploadFile(fileUrl.text, addToScene.checked) + enabled: fileUrlTextField.text != "" + onClicked: root.uploadClicked() } } } diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index 948bbb1295..75c9640589 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -24,6 +24,7 @@ ModalWindow { // For text boxes property alias placeholderText: textResult.placeholderText + property alias prefilledText: textResult.text // For combo boxes property bool editable: true; From 169af80bc09cdaa8dddefc1fc9619945918886a6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 17:09:37 -0800 Subject: [PATCH 078/258] Add a couple dialogs --- interface/resources/qml/AssetServer.qml | 33 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 49c7bd4363..94aa739892 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -50,15 +50,35 @@ Window { print("addToWorld"); } function renameFile() { - print("renameFile"); + var object = desktop.inputDialog({ + label: "Enter new path:", + prefilledText: "atp:/myFolder/myFile.ext", + placeholderText: "Enter path here" + }); + object.selected.connect(function(destinationPath) { + console.log("Renaming " + "fileUrl" + " to " + destinationPath); + + + + + + }); } function deleteFile() { - print("deleteFile"); + var object = desktop.messageBox({ + text: "Deleting", + informativeText: "You are about to delete the following file:\n" + "test" + "\nDo you want to continue?" + }); + object.selected.connect(function(button) { + + + + }); } function chooseClicked() { - var browser = fileBrowserBuilder.createObject(desktop, { + var browser = desktop.fileDialog({ selectDirectory: false, folder: fileDialogHelper.pathToUrl(currentDirectory) }); @@ -67,6 +87,8 @@ Window { fileUrlTextField.text = fileDialogHelper.urlToPath(url); }); + + } function uploadClicked() { @@ -161,11 +183,6 @@ Window { name: "" spacing: hifi.dimensions.contentSpacing.y - Component { - id: fileBrowserBuilder; - FileDialog { selectDirectory: true } - } - HifiControls.TextField { id: fileUrlTextField anchors.left: parent.left From 380480d4ee119da67dbac84927ceee21472193fa Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Mar 2016 18:06:56 -0800 Subject: [PATCH 079/258] Add a couple more dialogs --- interface/resources/qml/AssetServer.qml | 50 +++++++++++++++++-------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 94aa739892..34f6502b40 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -50,13 +50,18 @@ Window { print("addToWorld"); } function renameFile() { + var path = scriptsModel.data(treeView.currentIndex, 0x100); + if (!path) { + return; + } + var object = desktop.inputDialog({ label: "Enter new path:", - prefilledText: "atp:/myFolder/myFile.ext", + prefilledText: path, placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { - console.log("Renaming " + "fileUrl" + " to " + destinationPath); + console.log("Renaming " + path + " to " + destinationPath); @@ -65,43 +70,56 @@ Window { }); } function deleteFile() { + var path = scriptsModel.data(treeView.currentIndex, 0x100); + if (!path) { + return; + } + var object = desktop.messageBox({ + icon: OriginalDialogs.StandardIcon.Question, + buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.No, text: "Deleting", - informativeText: "You are about to delete the following file:\n" + "test" + "\nDo you want to continue?" + informativeText: "You are about to delete the following file:\n" + + path + + "\nDo you want to continue?" }); object.selected.connect(function(button) { + if (button === OriginalDialogs.StandardButton.Yes) { + console.log("Deleting " + path); - + } }); } function chooseClicked() { var browser = desktop.fileDialog({ selectDirectory: false, - folder: fileDialogHelper.pathToUrl(currentDirectory) + dir: currentDirectory }); browser.selectedFile.connect(function(url){ - console.log(url); fileUrlTextField.text = fileDialogHelper.urlToPath(url); + currentDirectory = browser.dir; }); - - - } function uploadClicked() { var fileUrl = fileUrlTextField.text - var addToScene = addToSceneCheckBox.checked + var addToWorld = addToWorldCheckBox.checked + + var path = scriptsModel.data(treeView.currentIndex, 0x100); + var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; + var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); var object = desktop.inputDialog({ label: "Enter asset path:", - prefilledText: "atp:/myFolder/myFile.ext", + prefilledText: directory + filename, placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { - console.log("Uploading " + fileUrl + " to " + destinationPath + " (addToScene: " + addToScene + ")"); + console.log("Uploading " + fileUrl + " to " + destinationPath + " (addToWorld: " + addToWorld + ")"); @@ -216,19 +234,19 @@ Window { } HifiControls.CheckBox { - id: addToSceneCheckBox + id: addToWorldCheckBox anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x - text: "Add to scene on upload" + text: "Add to world on upload" checked: false } Item { // Take the uploadButton out of the column flow. id: uploadButtonContainer - anchors.top: addToSceneCheckBox.top + anchors.top: addToWorldCheckBox.top anchors.right: parent.right HifiControls.Button { @@ -245,6 +263,8 @@ Window { onClicked: root.uploadClicked() } } + + HifiControls.VerticalSpacer {} } } } From b8df8f170d568df88d301006f8a0963b98c32bda Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 10:16:15 -0800 Subject: [PATCH 080/258] Add HF username as default username for bugsplat --- interface/src/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index f45a6c08b9..ed924108ef 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -143,6 +143,14 @@ int main(int argc, const char* argv[]) { QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection); +#ifdef HAS_BUGSPLAT + AccountManager& accountManager = AccountManager::getInstance(); + mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1()); + QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { + mpSender.setDefaultUserName(newUsername); + }); +#endif + QTranslator translator; translator.load("i18n/interface_en"); app.installTranslator(&translator); From 806bae99aae2d32a51f227f9c0f1e47b8fbcbd3f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 10:18:22 -0800 Subject: [PATCH 081/258] Fix bugsplat username setting --- interface/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index ed924108ef..3a4807ad6a 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -145,9 +145,9 @@ int main(int argc, const char* argv[]) { #ifdef HAS_BUGSPLAT AccountManager& accountManager = AccountManager::getInstance(); - mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1()); + mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1().constData()); QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { - mpSender.setDefaultUserName(newUsername); + mpSender.setDefaultUserName(newUsername.toLatin1().constData()); }); #endif From d20cf12941fc075e05708b64385cf50e845e85f2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 10:16:15 -0800 Subject: [PATCH 082/258] Add HF username as default username for bugsplat --- interface/src/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index f45a6c08b9..ed924108ef 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -143,6 +143,14 @@ int main(int argc, const char* argv[]) { QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection); +#ifdef HAS_BUGSPLAT + AccountManager& accountManager = AccountManager::getInstance(); + mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1()); + QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { + mpSender.setDefaultUserName(newUsername); + }); +#endif + QTranslator translator; translator.load("i18n/interface_en"); app.installTranslator(&translator); From eb402eab758bb47165037ab809883bea11fccf2b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 10:18:22 -0800 Subject: [PATCH 083/258] Fix bugsplat username setting --- interface/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index ed924108ef..3a4807ad6a 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -145,9 +145,9 @@ int main(int argc, const char* argv[]) { #ifdef HAS_BUGSPLAT AccountManager& accountManager = AccountManager::getInstance(); - mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1()); + mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1().constData()); QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { - mpSender.setDefaultUserName(newUsername); + mpSender.setDefaultUserName(newUsername.toLatin1().constData()); }); #endif From 5a0beec1f5a3c4dc02f39ffcc6dce41030632187 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 9 Mar 2016 11:43:56 -0800 Subject: [PATCH 084/258] Replace old drag&drop with new UI --- interface/resources/qml/AssetServer.qml | 1 + interface/resources/qml/hifi/MenuOption.qml | 1 - interface/src/Application.cpp | 94 ++------------------- interface/src/Application.h | 4 +- interface/src/Menu.cpp | 12 --- interface/src/Menu.h | 1 - 6 files changed, 11 insertions(+), 102 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 34f6502b40..ea2a082c8a 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -35,6 +35,7 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter property var currentDirectory; + property alias currentFileUrl: fileUrlTextField.text; Settings { category: "Overlay.AssetServer" diff --git a/interface/resources/qml/hifi/MenuOption.qml b/interface/resources/qml/hifi/MenuOption.qml index 477197f57e..da28d1daf3 100644 --- a/interface/resources/qml/hifi/MenuOption.qml +++ b/interface/resources/qml/hifi/MenuOption.qml @@ -155,7 +155,6 @@ QtObject { readonly property string toolWindow: "Tool Window"; readonly property string transmitterDrive: "Transmitter Drive"; readonly property string turnWithHead: "Turn using Head"; - readonly property string uploadAsset: "Upload File to Asset Server"; readonly property string useAudioForMouth: "Use Audio for Mouth"; readonly property string useCamera: "Use Camera"; readonly property string velocityFilter: "Velocity Filter"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 85ae8604e8..a824c22b0f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -158,7 +158,6 @@ #include "Stars.h" #include "ui/AddressBarDialog.h" #include "ui/AvatarInputs.h" -#include "ui/AssetUploadDialogFactory.h" #include "ui/DialogsManager.h" #include "ui/LoginDialog.h" #include "ui/overlays/Cube3DOverlay.h" @@ -3937,9 +3936,6 @@ void Application::nodeAdded(SharedNodePointer node) { if (node->getType() == NodeType::AvatarMixer) { // new avatar mixer, send off our identity packet right away getMyAvatar()->sendIdentityPacket(); - } else if (node->getType() == NodeType::AssetServer) { - // the addition of an asset-server always re-enables the upload to asset server menu option - Menu::getInstance()->getActionForOption(MenuOption::UploadAsset)->setEnabled(true); } } @@ -3989,10 +3985,6 @@ void Application::nodeKilled(SharedNodePointer node) { } else if (node->getType() == NodeType::AvatarMixer) { // our avatar mixer has gone away - clear the hash of avatars DependencyManager::get()->clearOtherAvatars(); - } else if (node->getType() == NodeType::AssetServer - && !DependencyManager::get()->soloNodeOfType(NodeType::AssetServer)) { - // this was our last asset server - disable the menu option to upload an asset - Menu::getInstance()->getActionForOption(MenuOption::UploadAsset)->setEnabled(false); } } void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket) { @@ -4218,7 +4210,10 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { } } - return defaultUpload && askToUploadAsset(urlString); + if (defaultUpload) { + toggleAssetServerWidget(urlString); + } + return defaultUpload; } void Application::setSessionUUID(const QUuid& sessionUUID) { @@ -4280,80 +4275,6 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { return true; } -bool Application::askToUploadAsset(const QString& filename) { - if (!DependencyManager::get()->getThisNodeCanRez()) { - OffscreenUi::warning(_window, "Failed Upload", - QString("You don't have upload rights on that domain.\n\n")); - return false; - } - - QUrl url { filename }; - if (auto upload = DependencyManager::get()->createUpload(url.toLocalFile())) { - - QMessageBox messageBox; - messageBox.setWindowTitle("Asset upload"); - messageBox.setText("You are about to upload the following file to the asset server:\n" + - url.toDisplayString()); - messageBox.setInformativeText("Do you want to continue?"); - messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - messageBox.setDefaultButton(QMessageBox::Ok); - - // Option to drop model in world for models - if (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive)) { - auto checkBox = new QCheckBox(&messageBox); - checkBox->setText("Add to scene"); - messageBox.setCheckBox(checkBox); - } - - if (messageBox.exec() != QMessageBox::Ok) { - upload->deleteLater(); - return false; - } - - // connect to the finished signal so we know when the AssetUpload is done - if (messageBox.checkBox() && (messageBox.checkBox()->checkState() == Qt::Checked)) { - // Custom behavior for models - QObject::connect(upload, &AssetUpload::finished, this, &Application::modelUploadFinished); - } else { - QObject::connect(upload, &AssetUpload::finished, - &AssetUploadDialogFactory::getInstance(), - &AssetUploadDialogFactory::handleUploadFinished); - } - - // start the upload now - upload->start(); - return true; - } - - // display a message box with the error - OffscreenUi::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename)); - return false; -} - -void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) { - auto fileInfo = QFileInfo(upload->getFilename()); - auto filename = fileInfo.fileName(); - - if ((upload->getError() == AssetUpload::NoError) && - (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || - filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive))) { - - auto entities = DependencyManager::get(); - - EntityItemProperties properties; - properties.setType(EntityTypes::Model); - properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(fileInfo.completeSuffix())); - properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); - properties.setName(QUrl(upload->getFilename()).fileName()); - - entities->addEntity(properties); - - upload->deleteLater(); - } else { - AssetUploadDialogFactory::getInstance().handleUploadFinished(upload, hash); - } -} - bool Application::askToWearAvatarAttachmentUrl(const QString& url) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); @@ -4453,9 +4374,12 @@ void Application::toggleRunningScriptsWidget() { //} } -void Application::toggleAssetServerWidget() { +void Application::toggleAssetServerWidget(QString filePath) { static const QUrl url("AssetServer.qml"); - DependencyManager::get()->show(url, "AssetServer"); + auto urlSetter = [=](QQmlContext* context, QObject* newObject){ + newObject->setProperty("currentFileUrl", filePath); + }; + DependencyManager::get()->show(url, "AssetServer", urlSetter); } void Application::packageModel() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 956eb5a1ea..e73524ee66 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -242,7 +242,7 @@ public slots: Q_INVOKABLE void loadScriptURLDialog(); void toggleLogDialog(); void toggleRunningScriptsWidget(); - void toggleAssetServerWidget(); + void toggleAssetServerWidget(QString filePath = ""); void handleLocalServerConnection(); void readArgumentsFromLocalSocket(); @@ -303,8 +303,6 @@ private slots: bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); bool askToLoadScript(const QString& scriptFilenameOrURL); - bool askToUploadAsset(const QString& asset); - void modelUploadFinished(AssetUpload* upload, const QString& hash); bool askToWearAvatarAttachmentUrl(const QString& url); void displayAvatarAttachmentWarning(const QString& message) const; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e9f45a6b9a..ab3add788d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -35,7 +35,6 @@ #include "MainWindow.h" #include "render/DrawStatus.h" #include "scripting/MenuScriptingInterface.h" -#include "ui/AssetUploadDialogFactory.h" #include "ui/DialogsManager.h" #include "ui/StandAloneJSConsole.h" #include "InterfaceLogging.h" @@ -365,17 +364,6 @@ Menu::Menu() { // Developer > Assets >>> MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets"); - auto& assetDialogFactory = AssetUploadDialogFactory::getInstance(); - assetDialogFactory.setDialogParent(this); - QAction* assetUpload = addActionToQMenuAndActionHash(assetDeveloperMenu, - MenuOption::UploadAsset, - 0, - &assetDialogFactory, - SLOT(showDialog())); - - // disable the asset upload action by default - it gets enabled only if asset server becomes present - assetUpload->setEnabled(false); - auto& atpMigrator = ATPAssetMigrator::getInstance(); atpMigrator.setDialogParent(this); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c605813753..b697bd5317 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -168,7 +168,6 @@ namespace MenuOption { const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; - const QString UploadAsset = "Upload File to Asset Server"; const QString UseAudioForMouth = "Use Audio for Mouth"; const QString UseCamera = "Use Camera"; const QString UseAnimPreAndPostRotations = "Use Anim Pre and Post Rotations"; From 03c38eada3952833bd3381fb91c8689f6de27411 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 12:06:33 -0800 Subject: [PATCH 085/258] add folder rename handling --- assignment-client/src/assets/AssetServer.cpp | 58 +++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 13257967ac..403941221d 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -511,6 +511,10 @@ bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { } } +bool pathIsFolder(const AssetPath& path) { + return path.endsWith('/'); +} + bool AssetServer::deleteMappings(const AssetPathList& paths) { // take a copy of the current mappings in case persistence of these deletes fails auto oldMappings = _fileMappings; @@ -538,23 +542,59 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { - // take the old hash to remove the old mapping - auto oldMapping = _fileMappings[oldPath].toString(); + if (pathIsFolder(oldPath)) { + if (!pathIsFolder(newPath)) { + // we were asked to rename a path to a folder to a path that isn't a folder, this is a fail + return false; + } - if (!oldMapping.isEmpty()) { - _fileMappings[newPath] = oldMapping; + // take a copy of the old mappings + auto oldMappings = _fileMappings; + + // iterate the current mappings and adjust any that matches the renamed folder + auto it = oldMappings.begin(); + while (it != oldMappings.end()) { + + if (it->toString().startsWith(oldPath)) { + auto oldKey = it.key(); + auto newKey = oldKey.replace(0, oldPath.size(), newPath); + + // remove the old version from the in memory file mappings + _fileMappings.remove(oldKey); + _fileMappings.insert(newKey, it.value()); + } + + ++it; + } if (writeMappingsToFile()) { - // persisted the renamed mapping, return success + // persisted the changed mappings return success return true; } else { - // we couldn't persist the renamed mapping, rollback and return failure - _fileMappings[oldPath] = oldMapping; + // couldn't persist the renamed paths, rollback and return failure + _fileMappings = oldMappings; return false; } } else { - // failed to find a mapping that was to be renamed, return failure - return false; + // take the old hash to remove the old mapping + auto oldMapping = _fileMappings[oldPath].toString(); + + if (!oldMapping.isEmpty()) { + _fileMappings[newPath] = oldMapping; + + if (writeMappingsToFile()) { + // persisted the renamed mapping, return success + return true; + } else { + // we couldn't persist the renamed mapping, rollback and return failure + _fileMappings[oldPath] = oldMapping; + + return false; + } + } else { + // failed to find a mapping that was to be renamed, return failure + return false; + } } } From a53b038ac2dee5616a36d4c08ba4d1392f51e95b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 12:10:36 -0800 Subject: [PATCH 086/258] add folder delete handling --- assignment-client/src/assets/AssetServer.cpp | 33 +++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 403941221d..ccd03aa2a3 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -521,11 +521,35 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { // enumerate the paths to delete and remove them all for (auto& path : paths) { - auto oldMapping = _fileMappings.take(path); - if (!oldMapping.isNull()) { - qDebug() << "Deleted a mapping:" << path << "=>" << oldMapping.toString(); + + // figure out if this path will delete a file or folder + if (pathIsFolder(path)) { + // enumerate the in memory file mappings and remove anything that matches + auto it = _fileMappings.begin(); + auto sizeBefore = _fileMappings.size(); + + while (it != _fileMappings.end()) { + if (it->toString().startsWith(path)) { + it = _fileMappings.erase(it); + } else { + ++it; + } + } + + auto sizeNow = _fileMappings.size(); + if (sizeBefore != sizeNow) { + qDebug() << "Deleted" << sizeBefore - sizeNow << "mappings in folder: " << path; + } else { + qDebug() << "Did not find any mappings in folder:" << path; + } + } else { - qDebug() << "Unable to delete a mapping that was not found:" << path; + auto oldMapping = _fileMappings.take(path); + if (!oldMapping.isNull()) { + qDebug() << "Deleted a mapping:" << path << "=>" << oldMapping.toString(); + } else { + qDebug() << "Unable to delete a mapping that was not found:" << path; + } } } @@ -542,6 +566,7 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { + // figure out if this rename is for a file or folder if (pathIsFolder(oldPath)) { if (!pathIsFolder(newPath)) { // we were asked to rename a path to a folder to a path that isn't a folder, this is a fail From 6b8a71f96a02cf25893881dfeef1bc1a87c16706 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 12:16:36 -0800 Subject: [PATCH 087/258] add debug for mapping operations --- assignment-client/src/assets/AssetServer.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ccd03aa2a3..9825e75c61 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -498,6 +498,7 @@ bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { // attempt to write to file if (writeMappingsToFile()) { // persistence succeeded, we are good to go + qDebug() << "Set mapping:" << path << "=>" << hash; return true; } else { // failed to persist this mapping to file - put back the old one in our in-memory representation @@ -507,6 +508,8 @@ bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { _fileMappings[path] = oldMapping; } + qWarning() << "Failed to persist mapping:" << path << "=>" << hash; + return false; } } @@ -578,8 +581,8 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa // iterate the current mappings and adjust any that matches the renamed folder auto it = oldMappings.begin(); - while (it != oldMappings.end()) { + while (it != oldMappings.end()) { if (it->toString().startsWith(oldPath)) { auto oldKey = it.key(); auto newKey = oldKey.replace(0, oldPath.size(), newPath); @@ -593,12 +596,16 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa } if (writeMappingsToFile()) { - // persisted the changed mappings return success + // persisted the changed mappings, return success + qDebug() << "Renamed mapping:" << oldPath << "=>" << newPath; + return true; } else { // couldn't persist the renamed paths, rollback and return failure _fileMappings = oldMappings; + qWarning() << "Failed to persist renamed mapping:" << oldPath << "=>" << newPath; + return false; } } else { @@ -610,11 +617,15 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa if (writeMappingsToFile()) { // persisted the renamed mapping, return success + qDebug() << "Renamed mapping:" << oldPath << "=>" << newPath; + return true; } else { // we couldn't persist the renamed mapping, rollback and return failure _fileMappings[oldPath] = oldMapping; + qDebug() << "Failed to persist renamed mapping:" << oldPath << "=>" << newPath; + return false; } } else { From 5a197838f4785020776964499800c5babf8a6637 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:14:39 -0800 Subject: [PATCH 088/258] add a deleteMapping call for single path to scripting interface --- libraries/script-engine/src/AssetScriptingInterface.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 287300cac8..d01eb939e2 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -29,6 +29,7 @@ public: Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); Q_INVOKABLE void getMapping(QString path, QScriptValue callback); Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); + Q_INVOKABLE void deleteMapping(QString path, QScriptValue callback) { deleteMappings(QStringList(path), callback); } Q_INVOKABLE void getAllMappings(QScriptValue callback); Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); protected: From a65d06c7ce2eba355bdd3abee72ac03e3ce2d6e1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:14:55 -0800 Subject: [PATCH 089/258] fix rename to take old mapping first --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 9825e75c61..ce95d7d4cb 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -610,7 +610,7 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa } } else { // take the old hash to remove the old mapping - auto oldMapping = _fileMappings[oldPath].toString(); + auto oldMapping = _fileMappings.take(oldPath).toString(); if (!oldMapping.isEmpty()) { _fileMappings[newPath] = oldMapping; From 5e9751c6ed2b78c15e378b6da3bf76b3dcd9526a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:28:05 -0800 Subject: [PATCH 090/258] bug fixes for rename/delete operations --- assignment-client/src/assets/AssetServer.cpp | 23 ++++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ce95d7d4cb..4f85a0f9e9 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -532,7 +532,7 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { auto sizeBefore = _fileMappings.size(); while (it != _fileMappings.end()) { - if (it->toString().startsWith(path)) { + if (it.key().startsWith(path)) { it = _fileMappings.erase(it); } else { ++it; @@ -573,6 +573,8 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa if (pathIsFolder(oldPath)) { if (!pathIsFolder(newPath)) { // we were asked to rename a path to a folder to a path that isn't a folder, this is a fail + qWarning() << "Cannot rename mapping from folder path" << oldPath << "to file path" << newPath; + return false; } @@ -583,12 +585,12 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa auto it = oldMappings.begin(); while (it != oldMappings.end()) { - if (it->toString().startsWith(oldPath)) { - auto oldKey = it.key(); - auto newKey = oldKey.replace(0, oldPath.size(), newPath); + if (it.key().startsWith(oldPath)) { + auto newKey = it.key(); + newKey.replace(0, oldPath.size(), newPath); // remove the old version from the in memory file mappings - _fileMappings.remove(oldKey); + _fileMappings.remove(it.key()); _fileMappings.insert(newKey, it.value()); } @@ -597,18 +599,25 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa if (writeMappingsToFile()) { // persisted the changed mappings, return success - qDebug() << "Renamed mapping:" << oldPath << "=>" << newPath; + qDebug() << "Renamed folder mapping:" << oldPath << "=>" << newPath; return true; } else { // couldn't persist the renamed paths, rollback and return failure _fileMappings = oldMappings; - qWarning() << "Failed to persist renamed mapping:" << oldPath << "=>" << newPath; + qWarning() << "Failed to persist renamed folder mapping:" << oldPath << "=>" << newPath; return false; } } else { + if (pathIsFolder(newPath)) { + // we were asked to rename a path to a file to a path that is a folder, this is a fail + qWarning() << "Cannot rename mapping from file path" << oldPath << "to folder path" << newPath; + + return false; + } + // take the old hash to remove the old mapping auto oldMapping = _fileMappings.take(oldPath).toString(); From d3dc81c7a09cb8b37d8506c56e3e853e91ef864b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:37:39 -0800 Subject: [PATCH 091/258] add delete debug, handle rename in memory state rollback --- assignment-client/src/assets/AssetServer.cpp | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4f85a0f9e9..5543dfeed5 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -561,6 +561,8 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { // persistence succeeded we are good to go return true; } else { + qWarning() << "Failed to persist deleted mappings, rolling back"; + // we didn't delete the previous mapping, put it back in our in-memory representation _fileMappings = oldMappings; @@ -619,10 +621,13 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa } // take the old hash to remove the old mapping - auto oldMapping = _fileMappings.take(oldPath).toString(); + auto oldSourceMapping = _fileMappings.take(oldPath).toString(); - if (!oldMapping.isEmpty()) { - _fileMappings[newPath] = oldMapping; + // in case we're overwriting, keep the current destination mapping for potential rollback + auto oldDestinationMapping = _fileMappings.value(newPath); + + if (!oldSourceMapping.isEmpty()) { + _fileMappings[newPath] = oldSourceMapping; if (writeMappingsToFile()) { // persisted the renamed mapping, return success @@ -631,7 +636,15 @@ bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPa return true; } else { // we couldn't persist the renamed mapping, rollback and return failure - _fileMappings[oldPath] = oldMapping; + _fileMappings[oldPath] = oldSourceMapping; + + if (!oldDestinationMapping.isNull()) { + // put back the overwritten mapping for the destination path + _fileMappings[newPath] = oldDestinationMapping.toString(); + } else { + // clear the new mapping + _fileMappings.remove(newPath); + } qDebug() << "Failed to persist renamed mapping:" << oldPath << "=>" << newPath; From a98640323722b8b17d9db345998b43aa26a82489 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 13:42:35 -0800 Subject: [PATCH 092/258] add a leading slash for faked migrated mappings --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 5543dfeed5..6dea815622 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -155,7 +155,7 @@ void AssetServer::performMappingMigration() { // add a new mapping with the old extension and a truncated version of the hash static const int TRUNCATED_HASH_NUM_CHAR = 16; - auto fakeFileName = hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; + auto fakeFileName = "/" + hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash; From fd5a5dd8f474ae419a1885e4b8ba8d6047f2814a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 16:53:04 -0800 Subject: [PATCH 093/258] Add QJSEngine compatible AssetMappingScriptInterface --- interface/src/Application.cpp | 1 + libraries/networking/src/AssetClient.cpp | 142 +++++++++++++++++++++++ libraries/networking/src/AssetClient.h | 34 ++++++ 3 files changed, 177 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 464e77ef6f..3551d58b53 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1267,6 +1267,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Vec3", new Vec3()); rootContext->setContextProperty("Uuid", new ScriptUUID()); + rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface(engine)); rootContext->setContextProperty("AvatarList", DependencyManager::get().data()); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 7c967e681a..42bfadee32 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -581,3 +581,145 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { _mappingCache.clear(); } + +void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { + QByteArray dataByteArray = data.toUtf8(); + auto upload = DependencyManager::get()->createUpload(dataByteArray); + if (!upload) { + qCWarning(asset_client) << "Error uploading file to asset server"; + return; + } + + QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { + if (callback.isFunction()) { + QString url = "atp://" + hash; + QScriptValueList args { url }; + callback.call(_engine->currentContext()->thisObject(), args); + } + }); + upload->start(); +} + +AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : + _engine(engine) +{ +} + +void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { + const QString ATP_SCHEME { "atp://" }; + + if (!urlString.startsWith(ATP_SCHEME)) { + return; + } + + // Make request to atp + auto path = urlString.right(urlString.length() - ATP_SCHEME.length()); + auto parts = path.split(".", QString::SkipEmptyParts); + auto hash = parts.length() > 0 ? parts[0] : ""; + + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + return; + } + + auto assetClient = DependencyManager::get(); + auto assetRequest = assetClient->createRequest(hash); + + if (!assetRequest) { + return; + } + + _pendingRequests << assetRequest; + + connect(assetRequest, &AssetRequest::finished, this, [this, callback](AssetRequest* request) mutable { + Q_ASSERT(request->getState() == AssetRequest::Finished); + + if (request->getError() == AssetRequest::Error::NoError) { + if (callback.isFunction()) { + QString data = QString::fromUtf8(request->getData()); + QScriptValueList args { data }; + callback.call(_engine->currentContext()->thisObject(), args); + } + } + + request->deleteLater(); + _pendingRequests.remove(request); + }); + + assetRequest->start(); +} + +AssetMappingsScriptingInterface::AssetMappingsScriptingInterface(QJSEngine* engine) : + _engine(engine) +{ +} + +void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingsRequest(paths); + + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto map = callback.engine()->newObject(); + + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } + + QJSValueList args { uint8_t(request->getError()), map }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 87b8646be1..cec1bd3872 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -12,6 +12,7 @@ #ifndef hifi_AssetClient_h #define hifi_AssetClient_h +#include #include #include @@ -106,4 +107,37 @@ private: friend class RenameMappingRequest; }; + +class AssetScriptingInterface : public QObject { + Q_OBJECT +public: + AssetScriptingInterface(QScriptEngine* engine); + + Q_INVOKABLE void uploadData(QString data, QScriptValue callback); + Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); +// Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); +// Q_INVOKABLE void getMapping(QString path, QScriptValue callback); +// Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); +// Q_INVOKABLE void getAllMappings(QScriptValue callback); +protected: + QSet _pendingRequests; + QScriptEngine* _engine; +}; + + +class AssetMappingsScriptingInterface : public QObject { + Q_OBJECT +public: + AssetMappingsScriptingInterface(QJSEngine* engine); + + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); + Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); + Q_INVOKABLE void getAllMappings(QJSValue callback); +protected: + QSet _pendingRequests; + QJSEngine* _engine; +}; + + #endif From 38edfe0557f96c3b1282c92acebc588687f43fdd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Mar 2016 16:53:18 -0800 Subject: [PATCH 094/258] Fix GetAllMappings reading --- libraries/networking/src/AssetClient.cpp | 144 +++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 42bfadee32..40838e3732 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -31,6 +31,150 @@ MessageID AssetClient::_currentID = 0; +void MappingRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + doStart(); +}; + +GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { +}; + +void GetMappingRequest::doStart() { + + auto assetClient = DependencyManager::get(); + + // Check cache + auto it = assetClient->_mappingCache.constFind(_path); + if (it != assetClient->_mappingCache.constEnd()) { + _hash = it.value(); + emit finished(this); + return; + } + + assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::AssetNotFound: + _error = NotFound; + break; + default: + _error = UnknownError; + break; + } + } + + if (!_error) { + _hash = message->read(SHA256_HASH_LENGTH).toHex(); + assetClient->_mappingCache[_path] = _hash; + } + emit finished(this); + }); +}; + +GetAllMappingsRequest::GetAllMappingsRequest() { +}; + +void GetAllMappingsRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + default: + _error = UnknownError; + break; + } + } + + + if (!error) { + int numberOfMappings; + message->readPrimitive(&numberOfMappings); + assetClient->_mappingCache.clear(); + for (auto i = 0; i < numberOfMappings; ++i) { + auto path = message->readString(); + auto hash = message->read(SHA256_HASH_LENGTH).toHex(); + _mappings[path] = hash; + assetClient->_mappingCache[path] = hash; + } + } + emit finished(this); + }); +}; + +SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : _path(path), _hash(hash) { +}; + +void SetMappingRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { + assetClient->_mappingCache[_path] = _hash; + } + emit finished(this); + }); +}; + +DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { +}; + +void DeleteMappingsRequest::doStart() { + auto assetClient = DependencyManager::get(); + assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { + if (!responseReceived) { + _error = NetworkError; + } else { + switch (error) { + case AssetServerError::NoError: + _error = NoError; + break; + case AssetServerError::PermissionDenied: + _error = PermissionDenied; + break; + default: + _error = UnknownError; + break; + } + } + + if (!error) { + // enumerate the paths and remove them from the cache + for (auto& path : _paths) { + assetClient->_mappingCache.remove(path); + } + } + emit finished(this); + }); +}; + AssetClient::AssetClient() { setCustomDeleter([](Dependency* dependency){ From 4da4fd889ae884dca0b83b4c565f6b6306cfec4c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 11:04:49 -0800 Subject: [PATCH 095/258] Add AssetMappingModel --- interface/resources/qml/AssetServer.qml | 3 +- libraries/networking/src/AssetClient.cpp | 99 +++++++++++++++++++++++- libraries/networking/src/AssetClient.h | 24 +++++- 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 34f6502b40..3e2dba164d 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,7 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var scriptsModel: scripts.scriptsModelFilter + property var scriptsModel: Assets.getAssetMappingModel() property var currentDirectory; Settings { @@ -45,6 +45,7 @@ Window { function reload() { print("reload"); + scriptsModel.refresh(); } function addToWorld() { print("addToWorld"); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 40838e3732..7eb49ff418 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -792,8 +792,11 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb assetRequest->start(); } +static int standardItemModelMetaTypeId = qRegisterMetaType("AssetMappingModel*"); + AssetMappingsScriptingInterface::AssetMappingsScriptingInterface(QJSEngine* engine) : - _engine(engine) + _engine(engine), + _assetMappingModel(this) { } @@ -867,3 +870,97 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { request->start(); } + +AssetMappingModel::AssetMappingModel(QObject* parent) { +} + +void AssetMappingModel::refresh() { + qDebug() << "Refreshing asset mapping model"; + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + qDebug() << "Got response"; + auto mappings = request->getMappings(); +// clear(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); + + QString prefix = parts[0]; + + QStandardItem* lastItem = nullptr; + + auto it = _pathToItemMap.find(prefix); + if (it == _pathToItemMap.end()) { + lastItem = new QStandardItem(parts[0]); + _pathToItemMap[prefix] = lastItem; + appendRow(lastItem); + } else { + lastItem = it.value(); + } + + if (length > 1) { + for (int i = 1; i < length; ++i) { + prefix += "/" + parts[i]; + + auto it = _pathToItemMap.find(prefix); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << prefix; + auto item = new QStandardItem(parts[i]); + lastItem->setChild(lastItem->rowCount(), 0, item); + lastItem = item; + _pathToItemMap[prefix] = lastItem; + } else { + lastItem = it.value(); + } + } + } + + Q_ASSERT(prefix == path); + } + }); + + request->start(); +} + + +// QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { +// if (row < 0 || column < 0) { +// return QModelIndex(); +// } + +// if (parent.isValid()) { +// auto item = static_cast(parent.internalPointer()); +// return createIndex(row, column, ) +// } +// return createIndex(row, column, getFolderNodes( +// static_cast(getTreeNodeFromIndex(parent))).at(row)); +// } + +// QModelIndex AssetMappingModel::parent(const QModelIndex& child) const { +// AssetMappingItem* parent = (static_cast(child.internalPointer()))->getParent(); +// if (!parent) { +// return QModelIndex(); +// } +// AssetMappingItem* grandParent = parent->getParent(); +// int row = getFolderNodes(grandParent).indexOf(parent); +// return createIndex(row, 0, parent); +// } + +// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { +// TreeNodeBase* node = getTreeNodeFromIndex(index); +// if (!node) { +// return QVariant(); +// } +// return QVariant(); +// } + +// int AssetMappingModel::rowCount(const QModelIndex& parent) const { +// return 1; +// } + +// int AssetMappingModel::columnCount(const QModelIndex& parent) const { +// return 1; +// } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index cec1bd3872..f48be7f962 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -12,6 +12,7 @@ #ifndef hifi_AssetClient_h #define hifi_AssetClient_h +#include #include #include @@ -125,11 +126,31 @@ protected: }; + class AssetMappingModel : public QStandardItemModel { + Q_OBJECT + public: + AssetMappingModel(QObject* parent = nullptr); + + Q_INVOKABLE void refresh(); + private: + QHash _pathToItemMap; + }; + + //class AssetMappingItem : public QStandardItem { + //Q_OBJECT + //public: + //AssetMappingItem(); + //}; + + class AssetMappingsScriptingInterface : public QObject { Q_OBJECT + Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) public: AssetMappingsScriptingInterface(QJSEngine* engine); + Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; }; + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); Q_INVOKABLE void getMapping(QString path, QJSValue callback); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); @@ -137,7 +158,6 @@ public: protected: QSet _pendingRequests; QJSEngine* _engine; + AssetMappingModel _assetMappingModel; }; - - #endif From 64bd41c37fd11c77c25cc6d8fc06184def0a3060 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 11:52:24 -0800 Subject: [PATCH 096/258] Add AssetMappingItem and extra data to items --- libraries/networking/src/AssetClient.cpp | 24 +++++++++++++++++------- libraries/networking/src/AssetClient.h | 22 ++++++++++++++-------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 7eb49ff418..710c1bf4bc 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -871,6 +871,13 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { request->start(); } +AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) + : name(name), + fullPath(fullPath), + isFolder(isFolder) { + +} + AssetMappingModel::AssetMappingModel(QObject* parent) { } @@ -880,9 +887,7 @@ void AssetMappingModel::refresh() { auto request = assetClient->createGetAllMappingsRequest(); connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { - qDebug() << "Got response"; auto mappings = request->getMappings(); -// clear(); for (auto& mapping : mappings) { auto& path = mapping.first; auto parts = path.split("/"); @@ -895,6 +900,8 @@ void AssetMappingModel::refresh() { auto it = _pathToItemMap.find(prefix); if (it == _pathToItemMap.end()) { lastItem = new QStandardItem(parts[0]); + lastItem->setData(parts[0], Qt::UserRole + 1); + lastItem->setData(prefix, Qt::UserRole + 2); _pathToItemMap[prefix] = lastItem; appendRow(lastItem); } else { @@ -909,6 +916,8 @@ void AssetMappingModel::refresh() { if (it == _pathToItemMap.end()) { qDebug() << "prefix not found: " << prefix; auto item = new QStandardItem(parts[i]); + item->setData(parts[i], Qt::UserRole + 1); + item->setData(prefix, Qt::UserRole + 2); lastItem->setChild(lastItem->rowCount(), 0, item); lastItem = item; _pathToItemMap[prefix] = lastItem; @@ -925,7 +934,6 @@ void AssetMappingModel::refresh() { request->start(); } - // QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { // if (row < 0 || column < 0) { // return QModelIndex(); @@ -950,13 +958,15 @@ void AssetMappingModel::refresh() { // } // QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { -// TreeNodeBase* node = getTreeNodeFromIndex(index); -// if (!node) { -// return QVariant(); +// if (index.isValid()) { +// AssetMappingItem* item = (static_cast(index.internalPointer())); +// if (item) { +// return item->name; +// } // } // return QVariant(); // } - +// // int AssetMappingModel::rowCount(const QModelIndex& parent) const { // return 1; // } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f48be7f962..08fcb099c4 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -126,23 +126,29 @@ protected: }; + class AssetMappingItem : public QStandardItem { + public: + AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); + + QString name; + QString fullPath; + bool isFolder; + }; + + class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: AssetMappingModel(QObject* parent = nullptr); + QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; + Q_INVOKABLE void refresh(); + private: - QHash _pathToItemMap; + QHash _pathToItemMap; }; - //class AssetMappingItem : public QStandardItem { - //Q_OBJECT - //public: - //AssetMappingItem(); - //}; - - class AssetMappingsScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) From 6bd7afc7b3232f7e9150d5d1ee02133296c30bd9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 9 Mar 2016 14:19:28 -0800 Subject: [PATCH 097/258] Confirm overrides --- interface/resources/qml/AssetServer.qml | 81 ++++++++++++++++++++----- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index ea2a082c8a..fdb9b81d87 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -44,10 +44,58 @@ Window { property alias directory: root.currentDirectory } + function doDeleteFile(path) { + console.log("Deleting " + path); + + } + function doUploadFile(path, mapping, addToWorld) { + console.log("Uploading " + path + " to " + mapping + " (addToWorld: " + addToWorld + ")"); + + + } + function doRenameFile(oldPath, newPath) { + console.log("Renaming " + oldPath + " to " + newPath); + + } + + function fileExists(destinationPath) { + return true; // TODO get correct value + } + + function askForOverride(path, callback) { + var object = desktop.messageBox({ + icon: OriginalDialogs.StandardIcon.Question, + buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.No, + text: "Override?", + informativeText: "The following file already exists:\n" + path + + "\nDo you want to override it?" + }); + object.selected.connect(function(button) { + if (button === OriginalDialogs.StandardButton.Yes) { + callback(); + } + }); + } + + function canAddToWorld() { + var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; + var path = scriptsModel.data(treeView.currentIndex, 0x100); + + return supportedExtensions.reduce(function(total, current) { + return total | new RegExp(current).test(path); + }, false); + } + function reload() { print("reload"); } function addToWorld() { + var path = scriptsModel.data(treeView.currentIndex, 0x100); + if (!path) { + return; + } + print("addToWorld"); } function renameFile() { @@ -62,12 +110,13 @@ Window { placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { - console.log("Renaming " + path + " to " + destinationPath); - - - - - + if (fileExists(destinationPath)) { + askForOverride(path, function() { + doRenameFile(path, destinationPath); + }); + } else { + doRenameFile(path, destinationPath); + } }); } function deleteFile() { @@ -87,10 +136,7 @@ Window { }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { - console.log("Deleting " + path); - - - + doDeleteFile(path); } }); } @@ -120,12 +166,13 @@ Window { placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { - console.log("Uploading " + fileUrl + " to " + destinationPath + " (addToWorld: " + addToWorld + ")"); - - - - - + if (fileExists(destinationPath)) { + askForOverride(fileUrl, function() { + doUploadFile(fileUrl, destinationPath, addToWorld); + }); + } else { + doUploadFile(fileUrl, destinationPath, addToWorld); + } }); } @@ -161,6 +208,8 @@ Window { height: 26 width: 120 + enabled: canAddToWorld() + onClicked: root.addToWorld() } From 96ba57a94609fb558978ae79543cc0b9036ea55e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 14:24:14 -0800 Subject: [PATCH 098/258] remove client side caching of ATP mappings --- libraries/networking/src/AssetClient.cpp | 4 --- libraries/networking/src/AssetClient.h | 2 -- libraries/networking/src/MappingRequest.cpp | 28 --------------------- 3 files changed, 34 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 7c967e681a..19b0be3917 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -91,8 +91,6 @@ void AssetClient::clearCache() { return; } - _mappingCache.clear(); - if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; cache->clear(); @@ -578,6 +576,4 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { messageMapIt->second.clear(); } } - - _mappingCache.clear(); } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 87b8646be1..299039ae8e 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -95,8 +95,6 @@ private: std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; - QHash _mappingCache; - friend class AssetRequest; friend class AssetUpload; friend class GetMappingRequest; diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 187694e134..0ab7d8fb36 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -32,14 +32,6 @@ void GetMappingRequest::doStart() { auto assetClient = DependencyManager::get(); - // Check cache - auto it = assetClient->_mappingCache.constFind(_path); - if (it != assetClient->_mappingCache.constEnd()) { - _hash = it.value(); - emit finished(this); - return; - } - assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { _error = NetworkError; @@ -59,7 +51,6 @@ void GetMappingRequest::doStart() { if (!_error) { _hash = message->read(SHA256_HASH_LENGTH).toHex(); - assetClient->_mappingCache[_path] = _hash; } emit finished(this); }); @@ -88,12 +79,10 @@ void GetAllMappingsRequest::doStart() { if (!error) { int numberOfMappings; message->readPrimitive(&numberOfMappings); - assetClient->_mappingCache.clear(); for (auto i = 0; i < numberOfMappings; ++i) { auto path = message->readString(); auto hash = message->readString(); _mappings[path] = hash; - assetClient->_mappingCache[path] = hash; } } emit finished(this); @@ -122,9 +111,6 @@ void SetMappingRequest::doStart() { } } - if (!error) { - assetClient->_mappingCache[_path] = _hash; - } emit finished(this); }); }; @@ -151,12 +137,6 @@ void DeleteMappingsRequest::doStart() { } } - if (!error) { - // enumerate the paths and remove them from the cache - for (auto& path : _paths) { - assetClient->_mappingCache.remove(path); - } - } emit finished(this); }); }; @@ -189,14 +169,6 @@ void RenameMappingRequest::doStart() { } } - if (!error) { - // take the hash mapped for the old path from the cache - auto hash = assetClient->_mappingCache.take(_oldPath); - if (!hash.isEmpty()) { - // use the hash mapped for the old path for the new path - assetClient->_mappingCache[_newPath] = hash; - } - } emit finished(this); }); } From e2b976d9f15903b41af6b839d540767dfe61402c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 14:24:35 -0800 Subject: [PATCH 099/258] remove debug, fix asset find bug for incorrect folder --- assignment-client/src/assets/AssetServer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 13257967ac..2218c5b5e3 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -220,12 +220,10 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode auto it = _fileMappings.find(assetPath); if (it != _fileMappings.end()) { auto assetHash = it->toString(); - qDebug() << "Found mapping for: " << assetPath << "=>" << assetHash; replyPacket.writePrimitive(AssetServerError::NoError); replyPacket.write(QByteArray::fromHex(assetHash.toUtf8())); } else { - qDebug() << "Mapping not found for: " << assetPath; replyPacket.writePrimitive(AssetServerError::AssetNotFound); } } @@ -314,7 +312,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh replyPacket->write(assetHash); QString fileName = QString(hexHash); - QFileInfo fileInfo { _resourcesDirectory.filePath(fileName) }; + QFileInfo fileInfo { _filesDirectory.filePath(fileName) }; if (fileInfo.exists() && fileInfo.isReadable()) { qDebug() << "Opening file: " << fileInfo.filePath(); From f5497aa1e7d0ed7d281cc4bb11008b0ca41f2450 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 13:55:33 -0800 Subject: [PATCH 100/258] Add new AssetMappingsScriptingInterface and add mappings model --- interface/resources/qml/AssetServer.qml | 5 + interface/src/Application.cpp | 8 +- libraries/networking/src/AssetClient.cpp | 393 ------------------ libraries/networking/src/AssetClient.h | 58 --- libraries/networking/src/MappingRequest.cpp | 12 +- .../src/AssetMappingsScriptingInterface.cpp | 218 ++++++++++ .../src/AssetMappingsScriptingInterface.h | 64 +++ .../src/AssetScriptingInterface.cpp | 87 ---- .../src/AssetScriptingInterface.h | 5 - 9 files changed, 298 insertions(+), 552 deletions(-) create mode 100644 libraries/script-engine/src/AssetMappingsScriptingInterface.cpp create mode 100644 libraries/script-engine/src/AssetMappingsScriptingInterface.h diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3e2dba164d..d773d6f86a 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -72,6 +72,7 @@ Window { } function deleteFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); + print(path); if (!path) { return; } @@ -89,6 +90,10 @@ Window { if (button === OriginalDialogs.StandardButton.Yes) { console.log("Deleting " + path); + Assets.deleteMappings([path], function(err) { + print("Finished deleting path: ", path, err); + reload(); + }); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3551d58b53..abeff8ade6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -413,6 +414,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(true, qApp, qApp); DependencyManager::set(); @@ -1267,7 +1269,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Vec3", new Vec3()); rootContext->setContextProperty("Uuid", new ScriptUUID()); - rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface(engine)); + rootContext->setContextProperty("Assets", DependencyManager::get().data()); rootContext->setContextProperty("AvatarList", DependencyManager::get().data()); @@ -4288,8 +4290,8 @@ bool Application::askToSetAvatarUrl(const QString& url) { case FSTReader::HEAD_AND_BODY_MODEL: ok = QMessageBox::Ok == OffscreenUi::question("Set Avatar", - "Would you like to use '" + modelName + "' for your avatar?", - QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + "Would you like to use '" + modelName + "' for your avatar?", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); break; default: diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 710c1bf4bc..7c967e681a 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -31,150 +31,6 @@ MessageID AssetClient::_currentID = 0; -void MappingRequest::start() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - return; - } - doStart(); -}; - -GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { -}; - -void GetMappingRequest::doStart() { - - auto assetClient = DependencyManager::get(); - - // Check cache - auto it = assetClient->_mappingCache.constFind(_path); - if (it != assetClient->_mappingCache.constEnd()) { - _hash = it.value(); - emit finished(this); - return; - } - - assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - case AssetServerError::AssetNotFound: - _error = NotFound; - break; - default: - _error = UnknownError; - break; - } - } - - if (!_error) { - _hash = message->read(SHA256_HASH_LENGTH).toHex(); - assetClient->_mappingCache[_path] = _hash; - } - emit finished(this); - }); -}; - -GetAllMappingsRequest::GetAllMappingsRequest() { -}; - -void GetAllMappingsRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->getAllAssetMappings([this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - default: - _error = UnknownError; - break; - } - } - - - if (!error) { - int numberOfMappings; - message->readPrimitive(&numberOfMappings); - assetClient->_mappingCache.clear(); - for (auto i = 0; i < numberOfMappings; ++i) { - auto path = message->readString(); - auto hash = message->read(SHA256_HASH_LENGTH).toHex(); - _mappings[path] = hash; - assetClient->_mappingCache[path] = hash; - } - } - emit finished(this); - }); -}; - -SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : _path(path), _hash(hash) { -}; - -void SetMappingRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - case AssetServerError::PermissionDenied: - _error = PermissionDenied; - break; - default: - _error = UnknownError; - break; - } - } - - if (!error) { - assetClient->_mappingCache[_path] = _hash; - } - emit finished(this); - }); -}; - -DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { -}; - -void DeleteMappingsRequest::doStart() { - auto assetClient = DependencyManager::get(); - assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { - if (!responseReceived) { - _error = NetworkError; - } else { - switch (error) { - case AssetServerError::NoError: - _error = NoError; - break; - case AssetServerError::PermissionDenied: - _error = PermissionDenied; - break; - default: - _error = UnknownError; - break; - } - } - - if (!error) { - // enumerate the paths and remove them from the cache - for (auto& path : _paths) { - assetClient->_mappingCache.remove(path); - } - } - emit finished(this); - }); -}; - AssetClient::AssetClient() { setCustomDeleter([](Dependency* dependency){ @@ -725,252 +581,3 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { _mappingCache.clear(); } - -void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { - QByteArray dataByteArray = data.toUtf8(); - auto upload = DependencyManager::get()->createUpload(dataByteArray); - if (!upload) { - qCWarning(asset_client) << "Error uploading file to asset server"; - return; - } - - QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { - if (callback.isFunction()) { - QString url = "atp://" + hash; - QScriptValueList args { url }; - callback.call(_engine->currentContext()->thisObject(), args); - } - }); - upload->start(); -} - -AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : - _engine(engine) -{ -} - -void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { - const QString ATP_SCHEME { "atp://" }; - - if (!urlString.startsWith(ATP_SCHEME)) { - return; - } - - // Make request to atp - auto path = urlString.right(urlString.length() - ATP_SCHEME.length()); - auto parts = path.split(".", QString::SkipEmptyParts); - auto hash = parts.length() > 0 ? parts[0] : ""; - - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - return; - } - - auto assetClient = DependencyManager::get(); - auto assetRequest = assetClient->createRequest(hash); - - if (!assetRequest) { - return; - } - - _pendingRequests << assetRequest; - - connect(assetRequest, &AssetRequest::finished, this, [this, callback](AssetRequest* request) mutable { - Q_ASSERT(request->getState() == AssetRequest::Finished); - - if (request->getError() == AssetRequest::Error::NoError) { - if (callback.isFunction()) { - QString data = QString::fromUtf8(request->getData()); - QScriptValueList args { data }; - callback.call(_engine->currentContext()->thisObject(), args); - } - } - - request->deleteLater(); - _pendingRequests.remove(request); - }); - - assetRequest->start(); -} - -static int standardItemModelMetaTypeId = qRegisterMetaType("AssetMappingModel*"); - -AssetMappingsScriptingInterface::AssetMappingsScriptingInterface(QJSEngine* engine) : - _engine(engine), - _assetMappingModel(this) -{ -} - -void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createSetMappingRequest(path, hash); - - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetMappingRequest(path); - - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; - - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createDeleteMappingsRequest(paths); - - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetAllMappingsRequest(); - - connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto map = callback.engine()->newObject(); - - for (auto& kv : mappings ) { - map.setProperty(kv.first, kv.second); - } - - QJSValueList args { uint8_t(request->getError()), map }; - - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); -} - -AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) - : name(name), - fullPath(fullPath), - isFolder(isFolder) { - -} - -AssetMappingModel::AssetMappingModel(QObject* parent) { -} - -void AssetMappingModel::refresh() { - qDebug() << "Refreshing asset mapping model"; - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetAllMappingsRequest(); - - connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - for (auto& mapping : mappings) { - auto& path = mapping.first; - auto parts = path.split("/"); - auto length = parts.length(); - - QString prefix = parts[0]; - - QStandardItem* lastItem = nullptr; - - auto it = _pathToItemMap.find(prefix); - if (it == _pathToItemMap.end()) { - lastItem = new QStandardItem(parts[0]); - lastItem->setData(parts[0], Qt::UserRole + 1); - lastItem->setData(prefix, Qt::UserRole + 2); - _pathToItemMap[prefix] = lastItem; - appendRow(lastItem); - } else { - lastItem = it.value(); - } - - if (length > 1) { - for (int i = 1; i < length; ++i) { - prefix += "/" + parts[i]; - - auto it = _pathToItemMap.find(prefix); - if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << prefix; - auto item = new QStandardItem(parts[i]); - item->setData(parts[i], Qt::UserRole + 1); - item->setData(prefix, Qt::UserRole + 2); - lastItem->setChild(lastItem->rowCount(), 0, item); - lastItem = item; - _pathToItemMap[prefix] = lastItem; - } else { - lastItem = it.value(); - } - } - } - - Q_ASSERT(prefix == path); - } - }); - - request->start(); -} - -// QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { -// if (row < 0 || column < 0) { -// return QModelIndex(); -// } - -// if (parent.isValid()) { -// auto item = static_cast(parent.internalPointer()); -// return createIndex(row, column, ) -// } -// return createIndex(row, column, getFolderNodes( -// static_cast(getTreeNodeFromIndex(parent))).at(row)); -// } - -// QModelIndex AssetMappingModel::parent(const QModelIndex& child) const { -// AssetMappingItem* parent = (static_cast(child.internalPointer()))->getParent(); -// if (!parent) { -// return QModelIndex(); -// } -// AssetMappingItem* grandParent = parent->getParent(); -// int row = getFolderNodes(grandParent).indexOf(parent); -// return createIndex(row, 0, parent); -// } - -// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { -// if (index.isValid()) { -// AssetMappingItem* item = (static_cast(index.internalPointer())); -// if (item) { -// return item->name; -// } -// } -// return QVariant(); -// } -// -// int AssetMappingModel::rowCount(const QModelIndex& parent) const { -// return 1; -// } - -// int AssetMappingModel::columnCount(const QModelIndex& parent) const { -// return 1; -// } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 08fcb099c4..9e34774816 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -108,62 +108,4 @@ private: friend class RenameMappingRequest; }; - -class AssetScriptingInterface : public QObject { - Q_OBJECT -public: - AssetScriptingInterface(QScriptEngine* engine); - - Q_INVOKABLE void uploadData(QString data, QScriptValue callback); - Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); -// Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); -// Q_INVOKABLE void getMapping(QString path, QScriptValue callback); -// Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); -// Q_INVOKABLE void getAllMappings(QScriptValue callback); -protected: - QSet _pendingRequests; - QScriptEngine* _engine; -}; - - - class AssetMappingItem : public QStandardItem { - public: - AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); - - QString name; - QString fullPath; - bool isFolder; - }; - - - class AssetMappingModel : public QStandardItemModel { - Q_OBJECT - public: - AssetMappingModel(QObject* parent = nullptr); - - QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; - - Q_INVOKABLE void refresh(); - - private: - QHash _pathToItemMap; - }; - -class AssetMappingsScriptingInterface : public QObject { - Q_OBJECT - Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) -public: - AssetMappingsScriptingInterface(QJSEngine* engine); - - Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; }; - - Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); - Q_INVOKABLE void getMapping(QString path, QJSValue callback); - Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); - Q_INVOKABLE void getAllMappings(QJSValue callback); -protected: - QSet _pendingRequests; - QJSEngine* _engine; - AssetMappingModel _assetMappingModel; -}; #endif diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 187694e134..73ea1483b0 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -50,7 +50,7 @@ void GetMappingRequest::doStart() { break; case AssetServerError::AssetNotFound: _error = NotFound; - break; + break default: _error = UnknownError; break; @@ -85,13 +85,13 @@ void GetAllMappingsRequest::doStart() { } - if (!error) { + if (!_error) { int numberOfMappings; message->readPrimitive(&numberOfMappings); assetClient->_mappingCache.clear(); for (auto i = 0; i < numberOfMappings; ++i) { auto path = message->readString(); - auto hash = message->readString(); + auto hash = message->read(SHA256_HASH_LENGTH).toHex(); _mappings[path] = hash; assetClient->_mappingCache[path] = hash; } @@ -122,7 +122,7 @@ void SetMappingRequest::doStart() { } } - if (!error) { + if (!_error) { assetClient->_mappingCache[_path] = _hash; } emit finished(this); @@ -151,7 +151,7 @@ void DeleteMappingsRequest::doStart() { } } - if (!error) { + if (!_error) { // enumerate the paths and remove them from the cache for (auto& path : _paths) { assetClient->_mappingCache.remove(path); @@ -189,7 +189,7 @@ void RenameMappingRequest::doStart() { } } - if (!error) { + if (!_error) { // take the hash mapped for the old path from the cache auto hash = assetClient->_mappingCache.take(_oldPath); if (!hash.isEmpty()) { diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp new file mode 100644 index 0000000000..c8370170db --- /dev/null +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -0,0 +1,218 @@ +// +// AssetMappingsScriptingInterface.cpp +// libraries/script-engine/src +// +// Created by Ryan Huffman on 2016-03-09. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AssetMappingsScriptingInterface.h" + +#include + +#include +#include +#include +#include + +AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { +} + +void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingsRequest(paths); + + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto map = callback.engine()->newObject(); + + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } + + QJSValueList args { uint8_t(request->getError()), map }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString newPath, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createRenameMappingRequest(oldPath, newPath); + + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + + +AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) + : name(name), + fullPath(fullPath), + isFolder(isFolder) { + +} + +static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); + +AssetMappingModel::AssetMappingModel(QObject* parent) { +} + +void AssetMappingModel::refresh() { + qDebug() << "Refreshing asset mapping model"; + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); + + QString fullPath = parts[0]; + + QStandardItem* lastItem = nullptr; + + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + lastItem = new QStandardItem(parts[0]); + lastItem->setData(parts[0], Qt::UserRole + 1); + lastItem->setData(fullPath, Qt::UserRole + 2); + _pathToItemMap[fullPath] = lastItem; + appendRow(lastItem); + } + else { + lastItem = it.value(); + } + + if (length > 1) { + for (int i = 1; i < length; ++i) { + fullPath += "/" + parts[i]; + + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + lastItem->setChild(lastItem->rowCount(), 0, item); + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); + } + } + } + + Q_ASSERT(fullPath == path); + } + }); + + request->start(); +} + +// QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { +// if (row < 0 || column < 0) { +// return QModelIndex(); +// } + +// if (parent.isValid()) { +// auto item = static_cast(parent.internalPointer()); +// return createIndex(row, column, ) +// } +// return createIndex(row, column, getFolderNodes( +// static_cast(getTreeNodeFromIndex(parent))).at(row)); +// } + +// QModelIndex AssetMappingModel::parent(const QModelIndex& child) const { +// AssetMappingItem* parent = (static_cast(child.internalPointer()))->getParent(); +// if (!parent) { +// return QModelIndex(); +// } +// AssetMappingItem* grandParent = parent->getParent(); +// int row = getFolderNodes(grandParent).indexOf(parent); +// return createIndex(row, 0, parent); +// } + +// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { +// if (index.isValid()) { +// AssetMappingItem* item = (static_cast(index.internalPointer())); +// if (item) { +// return item->name; +// } +// } +// return QVariant(); +// } +// +// int AssetMappingModel::rowCount(const QModelIndex& parent) const { +// return 1; +// } + +// int AssetMappingModel::columnCount(const QModelIndex& parent) const { +// return 1; +// } diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h new file mode 100644 index 0000000000..66a31414bb --- /dev/null +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -0,0 +1,64 @@ +// +// AssetScriptingInterface.h +// libraries/script-engine/src +// +// Created by Ryan Huffman on 2016-03-09. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#ifndef hifi_AssetMappingsScriptingInterface_h +#define hifi_AssetMappingsScriptingInterface_h + +#include +#include + +#include + + class AssetMappingItem : public QStandardItem { + public: + AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); + + QString name; + QString fullPath; + bool isFolder; + }; + + + class AssetMappingModel : public QStandardItemModel { + Q_OBJECT + public: + AssetMappingModel(QObject* parent = nullptr); + +// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; + + Q_INVOKABLE void refresh(); + + private: + QHash _pathToItemMap; + }; + + +class AssetMappingsScriptingInterface : public QObject, public Dependency { + Q_OBJECT +public: + AssetMappingsScriptingInterface(); + + Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } + + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); + Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); + Q_INVOKABLE void getAllMappings(QJSValue callback); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback); +protected: + QSet _pendingRequests; + AssetMappingModel _assetMappingModel; +}; + + +#endif // hifi_AssetMappingsScriptingInterface_h diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index db29008976..fb315434fd 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -84,90 +84,3 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb assetRequest->start(); } - -void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createSetMappingRequest(path, hash); - - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetMappingRequest(path); - - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()), request->getHash() }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::deleteMappings(QStringList paths, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createDeleteMappingsRequest(paths); - - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::getAllMappings(QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetAllMappingsRequest(); - - connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto map = callback.engine()->newObject(); - - for (auto& kv : mappings ) { - map.setProperty(kv.first, kv.second); - } - - QScriptValueList args { uint8_t(request->getError()), map }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::renameMapping(QString oldPath, QString newPath, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 287300cac8..63b16fd51d 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -26,11 +26,6 @@ public: Q_INVOKABLE void uploadData(QString data, QScriptValue callback); Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); - Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); - Q_INVOKABLE void getMapping(QString path, QScriptValue callback); - Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); - Q_INVOKABLE void getAllMappings(QScriptValue callback); - Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); protected: QSet _pendingRequests; QScriptEngine* _engine; From d299ce2677ab6f0bdc205554c2c43726c8579648 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 14:56:56 -0800 Subject: [PATCH 101/258] Fix missing semicolon --- libraries/networking/src/MappingRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 73ea1483b0..9afa3e7432 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -50,7 +50,7 @@ void GetMappingRequest::doStart() { break; case AssetServerError::AssetNotFound: _error = NotFound; - break + break; default: _error = UnknownError; break; From f23057b1c04093f3b765709e1a8593eadf90ac8a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:29:17 -0800 Subject: [PATCH 102/258] Add renaming to Asset qml --- interface/resources/qml/AssetServer.qml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index d773d6f86a..d76374c10c 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,7 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var scriptsModel: Assets.getAssetMappingModel() + property var scriptsModel: Assets.mappingModel; property var currentDirectory; Settings { @@ -52,6 +52,7 @@ Window { } function renameFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); + print(path); if (!path) { return; } @@ -63,16 +64,15 @@ Window { }); object.selected.connect(function(destinationPath) { console.log("Renaming " + path + " to " + destinationPath); - - - - - + Assets.renameMapping(path, destinationPath, function(err) { + print("Finished rename: ", err); + reload(); + }); }); } function deleteFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); - print(path); + print(treeView.currentIndex, path); if (!path) { return; } @@ -94,8 +94,6 @@ Window { print("Finished deleting path: ", path, err); reload(); }); - - } }); } From ebc6c8ce44e2f4deeef96fd537dcf62f4acf7e32 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:29:51 -0800 Subject: [PATCH 103/258] Add proper model updating to asset mapping model --- .../src/AssetMappingsScriptingInterface.cpp | 91 +++++++++++++------ .../src/AssetMappingsScriptingInterface.h | 5 +- 2 files changed, 67 insertions(+), 29 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index c8370170db..c5b165d7f6 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -20,6 +20,9 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { } +AssetMappingsScriptingInterface::~AssetMappingsScriptingInterface() { + qDebug() << "Destroying mapping interface"; +} void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); @@ -118,7 +121,11 @@ AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); -AssetMappingModel::AssetMappingModel(QObject* parent) { +AssetMappingModel::AssetMappingModel() { +} + +AssetMappingModel::~AssetMappingModel() { + qDebug() << " DEST"; } void AssetMappingModel::refresh() { @@ -128,49 +135,77 @@ void AssetMappingModel::refresh() { connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { auto mappings = request->getMappings(); + auto existingPaths = _pathToItemMap.keys(); for (auto& mapping : mappings) { auto& path = mapping.first; auto parts = path.split("/"); auto length = parts.length(); - QString fullPath = parts[0]; + existingPaths.removeOne(mapping.first); + + QString fullPath = "";// parts[0]; QStandardItem* lastItem = nullptr; - auto it = _pathToItemMap.find(fullPath); - if (it == _pathToItemMap.end()) { - lastItem = new QStandardItem(parts[0]); - lastItem->setData(parts[0], Qt::UserRole + 1); - lastItem->setData(fullPath, Qt::UserRole + 2); - _pathToItemMap[fullPath] = lastItem; - appendRow(lastItem); - } - else { - lastItem = it.value(); - } + for (int i = 0; i < length; ++i) { + fullPath += (i == 0 ? "" : "/") + parts[i]; - if (length > 1) { - for (int i = 1; i < length; ++i) { - fullPath += "/" + parts[i]; - - auto it = _pathToItemMap.find(fullPath); - if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << fullPath; - auto item = new QStandardItem(parts[i]); - bool isFolder = i < length - 1; - item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + item->setData(isFolder, Qt::UserRole + 1); + if (lastItem) { lastItem->setChild(lastItem->rowCount(), 0, item); - lastItem = item; - _pathToItemMap[fullPath] = lastItem; - } - else { - lastItem = it.value(); + } else { + appendRow(item); } + + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); } } Q_ASSERT(fullPath == path); } + for (auto& path : existingPaths) { + Q_ASSERT(_pathToItemMap.contains(path)); + auto item = _pathToItemMap[path]; + if (item->data(Qt::UserRole + 1).toBool()) { + continue; + } + + qDebug() << "removing existing: " << path; + + while (item) { + // During each iteration, delete item + QStandardItem* nextItem = nullptr; + + auto parent = item->parent(); + if (parent) { + parent->removeRow(item->row()); + if (parent->rowCount() > 0) { + // The parent still contains children, set the nextItem to null so we stop processing + nextItem = nullptr; + } else { + nextItem = parent; + } + } else { + removeRow(item->row()); + } + + _pathToItemMap.remove(path); + //delete item; + + item = nextItem; + } + //removeitem->index(); + } }); request->start(); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 66a31414bb..3afdab35cf 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -32,7 +32,8 @@ class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: - AssetMappingModel(QObject* parent = nullptr); + AssetMappingModel(); + ~AssetMappingModel(); // QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; @@ -45,8 +46,10 @@ class AssetMappingsScriptingInterface : public QObject, public Dependency { Q_OBJECT + Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) public: AssetMappingsScriptingInterface(); + ~AssetMappingsScriptingInterface(); Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } From 232bfc9061ebc691abf9d19d1aa62575ca856ddb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:44:31 -0800 Subject: [PATCH 104/258] Cleanup AssetServer qml --- interface/resources/qml/AssetServer.qml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 8134d78b26..54f7a10b25 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -47,7 +47,7 @@ Window { function doDeleteFile(path) { console.log("Deleting " + path); - Assets.deleteMappings([path], function(err) { + Assets.deleteMappings(path, function(err) { print("Finished deleting path: ", path, err); reload(); }); @@ -61,8 +61,7 @@ Window { function doRenameFile(oldPath, newPath) { console.log("Renaming " + oldPath + " to " + newPath); - console.log("Renaming " + path + " to " + destinationPath); - Assets.renameMapping(path, destinationPath, function(err) { + Assets.renameMapping(oldPath, destinationPath, function(err) { print("Finished rename: ", err); reload(); }); @@ -111,7 +110,6 @@ Window { } function renameFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); - print(path); if (!path) { return; } @@ -133,7 +131,6 @@ Window { } function deleteFile() { var path = scriptsModel.data(treeView.currentIndex, 0x100); - print(treeView.currentIndex, path); if (!path) { return; } From 3467e06199be0af83f642ebeb57c3292e7283339 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:44:41 -0800 Subject: [PATCH 105/258] Fix bugs in mapping model update --- .../src/AssetMappingsScriptingInterface.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index c5b165d7f6..8dc40b0df1 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -173,15 +173,24 @@ void AssetMappingModel::refresh() { Q_ASSERT(fullPath == path); } + + // Remove folders from list + auto it = existingPaths.begin(); + while (it != existingPaths.end()) { + auto item = _pathToItemMap[*it]; + if (item->data(Qt::UserRole + 1).toBool()) { + it = existingPaths.erase(it); + } else { + ++it; + } + } + for (auto& path : existingPaths) { Q_ASSERT(_pathToItemMap.contains(path)); - auto item = _pathToItemMap[path]; - if (item->data(Qt::UserRole + 1).toBool()) { - continue; - } - qDebug() << "removing existing: " << path; + auto item = _pathToItemMap[path]; + while (item) { // During each iteration, delete item QStandardItem* nextItem = nullptr; From fa66c0a5211cf377da783a39e342ad7653968dce Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:44:51 -0800 Subject: [PATCH 106/258] Remove old model code --- .../src/AssetMappingsScriptingInterface.cpp | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 8dc40b0df1..7fab655e26 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -219,44 +219,3 @@ void AssetMappingModel::refresh() { request->start(); } - -// QModelIndex AssetMappingModel::index(int row, int column, const QModelIndex& parent) const { -// if (row < 0 || column < 0) { -// return QModelIndex(); -// } - -// if (parent.isValid()) { -// auto item = static_cast(parent.internalPointer()); -// return createIndex(row, column, ) -// } -// return createIndex(row, column, getFolderNodes( -// static_cast(getTreeNodeFromIndex(parent))).at(row)); -// } - -// QModelIndex AssetMappingModel::parent(const QModelIndex& child) const { -// AssetMappingItem* parent = (static_cast(child.internalPointer()))->getParent(); -// if (!parent) { -// return QModelIndex(); -// } -// AssetMappingItem* grandParent = parent->getParent(); -// int row = getFolderNodes(grandParent).indexOf(parent); -// return createIndex(row, 0, parent); -// } - -// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const { -// if (index.isValid()) { -// AssetMappingItem* item = (static_cast(index.internalPointer())); -// if (item) { -// return item->name; -// } -// } -// return QVariant(); -// } -// -// int AssetMappingModel::rowCount(const QModelIndex& parent) const { -// return 1; -// } - -// int AssetMappingModel::columnCount(const QModelIndex& parent) const { -// return 1; -// } From dd52dd69d9fdb62919655834a6171ae65e4c1211 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:50:37 -0800 Subject: [PATCH 107/258] Fix rename mapping --- interface/resources/qml/AssetServer.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 54f7a10b25..f9cc566d39 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -61,7 +61,7 @@ Window { function doRenameFile(oldPath, newPath) { console.log("Renaming " + oldPath + " to " + newPath); - Assets.renameMapping(oldPath, destinationPath, function(err) { + Assets.renameMapping(oldPath, newPath, function(err) { print("Finished rename: ", err); reload(); }); @@ -121,7 +121,7 @@ Window { }); object.selected.connect(function(destinationPath) { if (fileExists(destinationPath)) { - askForOverride(path, function() { + askForOverride(destinationPath, function() { doRenameFile(path, destinationPath); }); } else { From 738ae54e8dafbbc85b939a315ed44375d3baf345 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 9 Mar 2016 16:56:28 -0800 Subject: [PATCH 108/258] Remove comment --- libraries/script-engine/src/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 7fab655e26..4dfc99b13f 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -143,7 +143,7 @@ void AssetMappingModel::refresh() { existingPaths.removeOne(mapping.first); - QString fullPath = "";// parts[0]; + QString fullPath = ""; QStandardItem* lastItem = nullptr; From 85fe1349ebb82ac43ee2db463aa26a864519d876 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 16:58:53 -0800 Subject: [PATCH 109/258] fix filename in header comment for AssetMappingsScriptingInterface --- libraries/script-engine/src/AssetMappingsScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 0bf98f47cc..797f099fb5 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -1,5 +1,5 @@ // -// AssetScriptingInterface.h +// AssetMappingsScriptingInterface.h // libraries/script-engine/src // // Created by Ryan Huffman on 2016-03-09. From ea5349f7a00687b496d026ec276f2fe0c911caca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 16:59:31 -0800 Subject: [PATCH 110/258] remove ctor and dtor for AssetMappingsScriptingInterface --- .../script-engine/src/AssetMappingsScriptingInterface.cpp | 6 ------ .../script-engine/src/AssetMappingsScriptingInterface.h | 3 --- 2 files changed, 9 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 4dfc99b13f..85ac84c244 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -18,12 +18,6 @@ #include #include -AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { -} -AssetMappingsScriptingInterface::~AssetMappingsScriptingInterface() { - qDebug() << "Destroying mapping interface"; -} - void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 797f099fb5..27d9ceff9f 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -48,9 +48,6 @@ class AssetMappingsScriptingInterface : public QObject, public Dependency { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) public: - AssetMappingsScriptingInterface(); - ~AssetMappingsScriptingInterface(); - Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); From 7b08ae37479a628e25b7857f377fe5a2955e9518 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 17:30:02 -0800 Subject: [PATCH 111/258] drop invalid mappings on AssetServer load --- assignment-client/src/assets/AssetServer.cpp | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index da1a7d3163..f37c6d706e 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -453,6 +453,30 @@ void AssetServer::loadMappingsFromFile() { if (error.error == QJsonParseError::NoError) { _fileMappings = jsonDocument.object().toVariantHash(); + // remove any mappings that don't match the expected format + auto it = _fileMappings.begin(); + while (it != _fileMappings.end()) { + bool shouldDrop = false; + + if (it.key()[0] != '/') { + qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a leading forward slash."; + shouldDrop = true; + } + + QRegExp hashFileRegex { "^[A-Fa-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; + + if (!hashFileRegex.exactMatch(it.value().toString())) { + qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a valid hash."; + shouldDrop = true; + } + + if (shouldDrop) { + it = _fileMappings.erase(it); + } else { + ++it; + } + } + qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath; return; } From 6f044e1cd31994566d85af097ad2dea81db3a4ba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 17:36:04 -0800 Subject: [PATCH 112/258] handling for leading slashes while loading mappings --- .../script-engine/src/AssetMappingsScriptingInterface.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 85ac84c244..3f2dd84721 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -137,12 +137,13 @@ void AssetMappingModel::refresh() { existingPaths.removeOne(mapping.first); - QString fullPath = ""; + QString fullPath = "/"; QStandardItem* lastItem = nullptr; - for (int i = 0; i < length; ++i) { - fullPath += (i == 0 ? "" : "/") + parts[i]; + // start index at 1 to avoid empty string from leading slash + for (int i = 1; i < length; ++i) { + fullPath += (i == 1 ? "" : "/") + parts[i]; auto it = _pathToItemMap.find(fullPath); if (it == _pathToItemMap.end()) { From 672f8ec1f7505bc223ae618126f49bb93cbcdbec Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 17:43:31 -0800 Subject: [PATCH 113/258] add checking for leading slash in mapping operations --- assignment-client/src/assets/AssetServer.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index f37c6d706e..e094b0d749 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -244,6 +244,7 @@ void AssetServer::handleGetAllMappingOperation(ReceivedMessage& message, SharedN void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { if (senderNode->getCanRez()) { QString assetPath = message.readString(); + auto assetHash = message.read(SHA256_HASH_LENGTH).toHex(); if (setMapping(assetPath, assetHash)) { @@ -511,6 +512,12 @@ bool AssetServer::writeMappingsToFile() { } bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { + + if (path[0] != '/') { + qWarning() << "Cannot set a mapping that does not have a leading forward slash:" << path; + return false; + } + // remember what the old mapping was in case persistence fails auto oldMapping = _fileMappings.value(path).toString(); @@ -593,6 +600,13 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { + if (oldPath[0] != '/' || newPath[0] != '/') { + qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:" + << oldPath << "=>" << newPath; + + return false; + } + // figure out if this rename is for a file or folder if (pathIsFolder(oldPath)) { if (!pathIsFolder(newPath)) { From ae3c0f6646d3623db698651ff15b9d3cf21a7619 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Mar 2016 18:01:10 -0800 Subject: [PATCH 114/258] add hash and path checking --- assignment-client/src/assets/AssetServer.cpp | 18 +++++++++++------- .../networking/src/AssetResourceRequest.cpp | 18 +++++++++--------- .../networking/src/AssetResourceRequest.h | 2 +- libraries/networking/src/AssetUtils.cpp | 10 ++++++++++ libraries/networking/src/AssetUtils.h | 6 ++++++ 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index e094b0d749..428920a44c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -117,7 +117,7 @@ void AssetServer::completeSetup() { // Check the asset directory to output some information about what we have auto files = _filesDirectory.entryList(QDir::Files); - QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; + QRegExp hashFileRegex { ASSET_HASH_REGEX_STRING }; auto hashedFiles = files.filter(hashFileRegex); qInfo() << "There are" << hashedFiles.size() << "asset files in the asset directory."; @@ -459,14 +459,13 @@ void AssetServer::loadMappingsFromFile() { while (it != _fileMappings.end()) { bool shouldDrop = false; - if (it.key()[0] != '/') { - qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a leading forward slash."; + if (!isValidPath(it.key())) { + qWarning() << "Will not keep mapping for" << it.key() << "since it is not a valid path."; shouldDrop = true; } - QRegExp hashFileRegex { "^[A-Fa-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}$" }; - if (!hashFileRegex.exactMatch(it.value().toString())) { + if (!isValidHash(it.value().toString())) { qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a valid hash."; shouldDrop = true; } @@ -513,8 +512,13 @@ bool AssetServer::writeMappingsToFile() { bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { - if (path[0] != '/') { - qWarning() << "Cannot set a mapping that does not have a leading forward slash:" << path; + if (!isValidPath(path)) { + qWarning() << "Cannot set a mapping for invalid path:" << path << "=>" << hash; + return false; + } + + if (!isValidHash(hash)) { + qWarning() << "Cannot set a mapping for invalid hash" << path << "=>" << hash; return false; } diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index a588bfb0d8..3cc7bdd4c7 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -25,11 +25,11 @@ AssetResourceRequest::~AssetResourceRequest() { } } -bool AssetResourceRequest::urlIsAssetPath() const { +bool AssetResourceRequest::urlIsAssetHash() const { static const QString ATP_HASH_REGEX_STRING = "^atp:([A-Fa-f0-9]{64})(\\.[\\w]+)?$"; QRegExp hashRegex { ATP_HASH_REGEX_STRING }; - return !hashRegex.exactMatch(_url.toString()); + return hashRegex.exactMatch(_url.toString()); } void AssetResourceRequest::doSend() { @@ -39,18 +39,18 @@ void AssetResourceRequest::doSend() { // We'll either have a hash or an ATP path to a file (that maps to a hash) - if (urlIsAssetPath()) { - // This is an ATP path, we'll need to figure out what the mapping is. - // This may incur a roundtrip to the asset-server, or it may return immediately from the cache in AssetClient. - - auto path = _url.path(); - requestMappingForPath(path); - } else { + if (urlIsAssetHash()) { // We've detected that this is a hash - simply use AssetClient to request that asset auto parts = _url.path().split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; requestHash(hash); + } else { + // This is an ATP path, we'll need to figure out what the mapping is. + // This may incur a roundtrip to the asset-server, or it may return immediately from the cache in AssetClient. + + auto path = _url.path(); + requestMappingForPath(path); } } diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 2fb8cfd3df..f517c57030 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -30,7 +30,7 @@ private slots: void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); private: - bool urlIsAssetPath() const; + bool urlIsAssetHash() const; void requestMappingForPath(const AssetPath& path); void requestHash(const AssetHash& hash); diff --git a/libraries/networking/src/AssetUtils.cpp b/libraries/networking/src/AssetUtils.cpp index cf1bdbe8f2..e25f357fcc 100644 --- a/libraries/networking/src/AssetUtils.cpp +++ b/libraries/networking/src/AssetUtils.cpp @@ -63,3 +63,13 @@ bool saveToCache(const QUrl& url, const QByteArray& file) { } return false; } + +bool isValidPath(const AssetPath& path) { + QRegExp pathRegex { ASSET_PATH_REGEX_STRING }; + return pathRegex.exactMatch(path); +} + +bool isValidHash(const AssetHash& hash) { + QRegExp hashRegex { ASSET_HASH_REGEX_STRING }; + return hashRegex.exactMatch(hash); +} diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 2495326b67..52ed7336c2 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -31,6 +31,9 @@ const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB +const QString ASSET_PATH_REGEX_STRING = "^\\/(?:[^\\/]|\\/(?!\\/))*$"; +const QString ASSET_HASH_REGEX_STRING = QString("^[a-fA-F0-9]{%1}$").arg(SHA256_HASH_HEX_LENGTH); + enum AssetServerError : uint8_t { NoError = 0, AssetNotFound, @@ -55,4 +58,7 @@ QByteArray hashData(const QByteArray& data); QByteArray loadFromCache(const QUrl& url); bool saveToCache(const QUrl& url, const QByteArray& file); +bool isValidPath(const AssetPath& path); +bool isValidHash(const QString& hashString); + #endif From 3e5e2eef177bd2f91edeff35de39e6b965ae130d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 08:18:17 -0800 Subject: [PATCH 115/258] Add mapping sorting, copying, and isKnownMapping --- interface/resources/qml/AssetServer.qml | 49 ++++++++++++++----- .../scripting/WindowScriptingInterface.cpp | 6 +++ .../src/scripting/WindowScriptingInterface.h | 1 + .../src/AssetMappingsScriptingInterface.cpp | 9 ++++ .../src/AssetMappingsScriptingInterface.h | 10 ++++ 5 files changed, 62 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index f9cc566d39..3ff5bb98f1 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,7 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var scriptsModel: Assets.mappingModel; + property var assetMappingsModel: Assets.proxyModel; property var currentDirectory; property alias currentFileUrl: fileUrlTextField.text; @@ -67,8 +67,8 @@ Window { }); } - function fileExists(destinationPath) { - return true; // TODO get correct value + function fileExists(path) { + return Assets.isKnownMapping(path); } function askForOverride(path, callback) { @@ -89,7 +89,7 @@ Window { function canAddToWorld() { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); return supportedExtensions.reduce(function(total, current) { return total | new RegExp(current).test(path); @@ -98,18 +98,25 @@ Window { function reload() { print("reload"); - scriptsModel.refresh(); + Assets.mappingModel.refresh(); } function addToWorld() { - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); if (!path) { return; } - - print("addToWorld"); } + + function copyURLToClipboard() { + var path = assetMappingsModel.data(treeView.currentIndex, 0x103); + if (!path) { + return; + } + Window.copyToClipboard(path); + } + function renameFile() { - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); if (!path) { return; } @@ -120,6 +127,9 @@ Window { placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { + if (path == destinationPath) { + return; + } if (fileExists(destinationPath)) { askForOverride(destinationPath, function() { doRenameFile(path, destinationPath); @@ -130,17 +140,20 @@ Window { }); } function deleteFile() { - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); if (!path) { return; } + var isFolder = assetMappingsModel.data(treeView.currentIndex, 0x101); + var typeString = isFolder ? 'folder' : 'file'; + var object = desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Question, buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, defaultButton: OriginalDialogs.StandardButton.No, text: "Deleting", - informativeText: "You are about to delete the following file:\n" + + informativeText: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?" }); @@ -166,7 +179,7 @@ Window { var fileUrl = fileUrlTextField.text var addToWorld = addToWorldCheckBox.checked - var path = scriptsModel.data(treeView.currentIndex, 0x100); + var path = assetMappingsModel.data(treeView.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); @@ -211,6 +224,16 @@ Window { onClicked: root.reload() } + HifiControls.GlyphButton { + glyph: hifi.glyphs.reload + color: hifi.buttons.white + colorScheme: root.colorScheme + height: 26 + width: 26 + + onClicked: root.copyURLToClipboard() + } + HifiControls.Button { text: "ADD TO WORLD" color: hifi.buttons.white @@ -249,7 +272,7 @@ Window { HifiControls.Tree { id: treeView height: 400 - treeModel: scriptsModel + treeModel: assetMappingsModel colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 4c9c0df1cb..0443c65453 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -139,3 +140,8 @@ int WindowScriptingInterface::getX() { int WindowScriptingInterface::getY() { return qApp->getWindow()->y(); } + +void WindowScriptingInterface::copyToClipboard(const QString& text) { + qDebug() << "Copying"; + QApplication::clipboard()->setText(text); +} diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 609915bdc7..0f51a484c4 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -40,6 +40,7 @@ public slots: QScriptValue prompt(const QString& message = "", const QString& defaultText = ""); QScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + void copyToClipboard(const QString& text); signals: void domainChanged(const QString& domainHostname); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 3f2dd84721..c7c5929121 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -18,6 +18,13 @@ #include #include +AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { + _proxyModel.setSourceModel(&_assetMappingModel); + _proxyModel.setSortRole(Qt::DisplayRole); + _proxyModel.setDynamicSortFilter(true); + _proxyModel.sort(0); +} + void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); @@ -152,6 +159,8 @@ void AssetMappingModel::refresh() { bool isFolder = i < length - 1; item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); item->setData(isFolder, Qt::UserRole + 1); + item->setData(parts[i], Qt::UserRole + 2); + item->setData("atp:" + fullPath, Qt::UserRole + 3); if (lastItem) { lastItem->setChild(lastItem->rowCount(), 0, item); } else { diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 27d9ceff9f..2d62f2d6e5 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -18,6 +18,7 @@ #include #include +#include class AssetMappingItem : public QStandardItem { public: @@ -39,6 +40,8 @@ Q_INVOKABLE void refresh(); + bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; + private: QHash _pathToItemMap; }; @@ -47,8 +50,14 @@ class AssetMappingsScriptingInterface : public QObject, public Dependency { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) + Q_PROPERTY(QAbstractProxyModel* proxyModel READ getProxyModel CONSTANT) public: + AssetMappingsScriptingInterface(); + Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } + Q_INVOKABLE QAbstractProxyModel* getProxyModel() { return &_proxyModel; } + + Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); }; Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); Q_INVOKABLE void getMapping(QString path, QJSValue callback); @@ -59,6 +68,7 @@ public: protected: QSet _pendingRequests; AssetMappingModel _assetMappingModel; + QSortFilterProxyModel _proxyModel; }; From f1919031dece5f17d0759c7dbc51a26423541599 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 08:57:37 -0800 Subject: [PATCH 116/258] error message boxes for mapping errors --- interface/resources/qml/AssetServer.qml | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3ff5bb98f1..43e5297477 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -48,7 +48,13 @@ Window { console.log("Deleting " + path); Assets.deleteMappings(path, function(err) { - print("Finished deleting path: ", path, err); + if (err) { + console.log("Error deleting path: ", path, err); + errorMessage("There was an error deleting:\n" + path + "\n\nPlease try again."); + } else { + console.log("Finished deleting path: ", path); + } + reload(); }); @@ -62,7 +68,13 @@ Window { console.log("Renaming " + oldPath + " to " + newPath); Assets.renameMapping(oldPath, newPath, function(err) { - print("Finished rename: ", err); + if (err) { + console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); + errorMessage("There was an error renaming:\n" + oldPath + " to " + newPath + "\n\nPlease try again."); + } else { + console.log("Finished rename: ", oldPath, "=>", newPath); + } + reload(); }); } @@ -199,6 +211,15 @@ Window { }); } + function errorMessage(message) { + desktop.messageBox({ + icon: OriginalDialogs.StandardIcon.Error, + buttons: OriginalDialogs.StandardButton.Ok, + text: "Error", + informativeText: message + }); + } + Column { width: pane.contentWidth From 899595183e249b72ae7891ae6d7191fea6fa481a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 09:02:45 -0800 Subject: [PATCH 117/258] add reload of mappings on component complete --- interface/resources/qml/AssetServer.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 43e5297477..16dc5846ab 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -44,6 +44,8 @@ Window { property alias directory: root.currentDirectory } + Component.onCompleted: reload() + function doDeleteFile(path) { console.log("Deleting " + path); From b42bec78dc329060564e98d33fdd2738ef70a1ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 10:25:20 -0800 Subject: [PATCH 118/258] Add Entities.addModelEntity --- libraries/entities/src/EntityScriptingInterface.cpp | 8 ++++++++ libraries/entities/src/EntityScriptingInterface.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 26f73eb65a..334295af16 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -178,6 +178,14 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties return id; } +QUuid EntityScriptingInterface::addModelEntity(const QString& modelUrl, const glm::vec3& position) { + EntityItemProperties properties; + properties.setType(EntityTypes::Model); + properties.setModelURL(modelUrl); + properties.setPosition(position); + return addEntity(properties); +} + EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { EntityPropertyFlags noSpecificProperties; return getEntityProperties(identity, noSpecificProperties); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 79d8f0a0b0..fda2aa7e59 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -84,6 +84,8 @@ public slots: /// adds a model with the specific properties Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties); + Q_INVOKABLE QUuid addModelEntity(const QString& modelUrl, const glm::vec3& position); + /// gets the current model properties for a specific model /// this function will not find return results in script engine contexts which don't have access to models Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID); From 0df05d273d5accd6c5e9845f7ede86f14a89754b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 10:25:51 -0800 Subject: [PATCH 119/258] Implement addToWorld in asset window --- interface/resources/qml/AssetServer.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3ff5bb98f1..0ce9cbee40 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -101,10 +101,12 @@ Window { Assets.mappingModel.refresh(); } function addToWorld() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); - if (!path) { + var url = assetMappingsModel.data(treeView.currentIndex, 0x102); + if (!url) { return; } + + Entities.addModelEntity(url, MyAvatar.position); } function copyURLToClipboard() { From 99718e9c4e5586bf8ac9f7a70b6db41bc463754b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:21:26 -0800 Subject: [PATCH 120/258] short circuit the mapping operations for invalid path/hash --- assignment-client/src/assets/AssetServer.cpp | 2 +- interface/resources/qml/AssetServer.qml | 28 +- libraries/networking/src/AssetClient.cpp | 30 +- libraries/networking/src/MappingRequest.cpp | 48 ++- libraries/networking/src/MappingRequest.h | 2 + .../src/AssetMappingsScriptingInterface.cpp | 278 ++++++++++-------- .../src/AssetMappingsScriptingInterface.h | 4 + .../src/AssetScriptingInterface.cpp | 4 +- 8 files changed, 250 insertions(+), 146 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 428920a44c..08cfa1252f 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -604,7 +604,7 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { - if (oldPath[0] != '/' || newPath[0] != '/') { + if (!isValidPath(oldPath) || !isValidPath(newPath)) { qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:" << oldPath << "=>" << newPath; diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 0ffa0dca7a..dc4c925130 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,8 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var assetMappingsModel: Assets.proxyModel; + property var assetProxyModel: Assets.proxyModel; + property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; property alias currentFileUrl: fileUrlTextField.text; @@ -44,7 +45,10 @@ Window { property alias directory: root.currentDirectory } - Component.onCompleted: reload() + Component.onCompleted: { + assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError) + reload() + } function doDeleteFile(path) { console.log("Deleting " + path); @@ -103,7 +107,7 @@ Window { function canAddToWorld() { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.currentIndex, 0x100); return supportedExtensions.reduce(function(total, current) { return total | new RegExp(current).test(path); @@ -114,6 +118,12 @@ Window { print("reload"); Assets.mappingModel.refresh(); } + + function handleGetMappingsError() { + errorMessage("There was a problem retreiving the list of assets from your Asset Server.\n" + + "Please make sure you are connected to the Asset Server and try again. "); + } + function addToWorld() { var url = assetMappingsModel.data(treeView.currentIndex, 0x102); if (!url) { @@ -124,7 +134,7 @@ Window { } function copyURLToClipboard() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x103); + var path = assetProxyModel.data(treeView.currentIndex, 0x103); if (!path) { return; } @@ -132,7 +142,7 @@ Window { } function renameFile() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.currentIndex, 0x100); if (!path) { return; } @@ -156,12 +166,12 @@ Window { }); } function deleteFile() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.currentIndex, 0x100); if (!path) { return; } - var isFolder = assetMappingsModel.data(treeView.currentIndex, 0x101); + var isFolder = assetProxyModel.data(treeView.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; var object = desktop.messageBox({ @@ -195,7 +205,7 @@ Window { var fileUrl = fileUrlTextField.text var addToWorld = addToWorldCheckBox.checked - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); @@ -297,7 +307,7 @@ Window { HifiControls.Tree { id: treeView height: 400 - treeModel: assetMappingsModel + treeModel: assetProxyModel colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 19b0be3917..79828cc235 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -138,6 +138,7 @@ bool haveAssetServer() { return true; } + GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { return new GetMappingRequest(path); } @@ -159,8 +160,8 @@ RenameMappingRequest* AssetClient::createRenameMappingRequest(const AssetPath& o } AssetRequest* AssetClient::createRequest(const AssetHash& hash) { - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - qCWarning(asset_client) << "Invalid hash size"; + if (isValidHash(hash)) { + qCWarning(asset_client) << "Invalid hash"; return nullptr; } @@ -364,9 +365,10 @@ bool AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallbac _pendingMappingRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) { @@ -386,9 +388,10 @@ bool AssetClient::getAllAssetMappings(MappingOperationCallback callback) { _pendingMappingRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) { @@ -414,9 +417,10 @@ bool AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperati _pendingMappingRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, MappingOperationCallback callback) { @@ -439,9 +443,10 @@ bool AssetClient::setAssetMapping(const QString& path, const AssetHash& hash, Ma _pendingMappingRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath& newPath, MappingOperationCallback callback) { @@ -465,9 +470,10 @@ bool AssetClient::renameAssetMapping(const AssetPath& oldPath, const AssetPath& return true; + } else { + callback(false, AssetServerError::NoError, QSharedPointer()); + return false; } - - return false; } bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) { diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index afa20e551c..6f76d1103f 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -30,6 +30,13 @@ GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { void GetMappingRequest::doStart() { + // short circuit the request if the path is invalid + if (!isValidPath(_path)) { + _error = MappingRequest::InvalidPath; + emit finished(this); + return; + } + auto assetClient = DependencyManager::get(); assetClient->getAssetMapping(_path, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { @@ -89,11 +96,26 @@ void GetAllMappingsRequest::doStart() { }); }; -SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : _path(path), _hash(hash) { +SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : + _path(path), + _hash(hash) +{ + }; void SetMappingRequest::doStart() { + + // short circuit the request if the hash or path are invalid + auto validPath = isValidPath(_path); + auto validHash = isValidHash(_hash); + if (!validPath || !validHash) { + _error = validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash; + emit finished(this); + return; + } + auto assetClient = DependencyManager::get(); + assetClient->setAssetMapping(_path, _hash, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { _error = NetworkError; @@ -119,7 +141,18 @@ DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _path }; void DeleteMappingsRequest::doStart() { + + // short circuit the request if any of the paths are invalid + for (auto& path : _paths) { + if (!isValidPath(path)) { + _error = MappingRequest::InvalidPath; + emit finished(this); + return; + } + } + auto assetClient = DependencyManager::get(); + assetClient->deleteAssetMappings(_paths, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { if (!responseReceived) { _error = NetworkError; @@ -142,14 +175,23 @@ void DeleteMappingsRequest::doStart() { }; RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : -_oldPath(oldPath), -_newPath(newPath) + _oldPath(oldPath), + _newPath(newPath) { } void RenameMappingRequest::doStart() { + + // short circuit the request if either of the paths are invalid + if (!isValidPath(_oldPath) || !isValidPath(_newPath)) { + _error = InvalidPath; + emit finished(this); + return; + } + auto assetClient = DependencyManager::get(); + assetClient->renameAssetMapping(_oldPath, _newPath, [this, assetClient](bool responseReceived, AssetServerError error, QSharedPointer message) { diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h index b9bd867712..c6a27e0274 100644 --- a/libraries/networking/src/MappingRequest.h +++ b/libraries/networking/src/MappingRequest.h @@ -26,6 +26,8 @@ public: NotFound, NetworkError, PermissionDenied, + InvalidPath, + InvalidHash, UnknownError }; diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index c7c5929121..fc21161f93 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -29,87 +29,117 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + if (request) { + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetMappingRequest(path); - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; + if (request) { + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createDeleteMappingsRequest(paths); - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + if (request) { + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto map = callback.engine()->newObject(); + if (request) { + connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto map = callback.engine()->newObject(); - for (auto& kv : mappings ) { - map.setProperty(kv.first, kv.second); - } + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } - QJSValueList args { uint8_t(request->getError()), map }; + QJSValueList args { uint8_t(request->getError()), map }; + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString newPath, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + if (request) { + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + request->start(); + } else { + // not connected to an Asset Server, return network error + QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - - request->deleteLater(); - - }); - - request->start(); + } } @@ -134,92 +164,102 @@ void AssetMappingModel::refresh() { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto existingPaths = _pathToItemMap.keys(); - for (auto& mapping : mappings) { - auto& path = mapping.first; - auto parts = path.split("/"); - auto length = parts.length(); + if (request) { + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + if (request->getError() == MappingRequest::NoError) { + auto mappings = request->getMappings(); + auto existingPaths = _pathToItemMap.keys(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); - existingPaths.removeOne(mapping.first); + existingPaths.removeOne(mapping.first); - QString fullPath = "/"; + QString fullPath = "/"; - QStandardItem* lastItem = nullptr; + QStandardItem* lastItem = nullptr; - // start index at 1 to avoid empty string from leading slash - for (int i = 1; i < length; ++i) { - fullPath += (i == 1 ? "" : "/") + parts[i]; + // start index at 1 to avoid empty string from leading slash + for (int i = 1; i < length; ++i) { + fullPath += (i == 1 ? "" : "/") + parts[i]; - auto it = _pathToItemMap.find(fullPath); - if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << fullPath; - auto item = new QStandardItem(parts[i]); - bool isFolder = i < length - 1; - item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); - item->setData(isFolder, Qt::UserRole + 1); - item->setData(parts[i], Qt::UserRole + 2); - item->setData("atp:" + fullPath, Qt::UserRole + 3); - if (lastItem) { - lastItem->setChild(lastItem->rowCount(), 0, item); - } else { - appendRow(item); + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + item->setData(isFolder, Qt::UserRole + 1); + item->setData(parts[i], Qt::UserRole + 2); + item->setData("atp:" + fullPath, Qt::UserRole + 3); + if (lastItem) { + lastItem->setChild(lastItem->rowCount(), 0, item); + } else { + appendRow(item); + } + + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); + } } - lastItem = item; - _pathToItemMap[fullPath] = lastItem; + Q_ASSERT(fullPath == path); } - else { - lastItem = it.value(); + + // Remove folders from list + auto it = existingPaths.begin(); + while (it != existingPaths.end()) { + auto item = _pathToItemMap[*it]; + if (item->data(Qt::UserRole + 1).toBool()) { + it = existingPaths.erase(it); + } else { + ++it; + } } - } - Q_ASSERT(fullPath == path); - } + for (auto& path : existingPaths) { + Q_ASSERT(_pathToItemMap.contains(path)); + qDebug() << "removing existing: " << path; - // Remove folders from list - auto it = existingPaths.begin(); - while (it != existingPaths.end()) { - auto item = _pathToItemMap[*it]; - if (item->data(Qt::UserRole + 1).toBool()) { - it = existingPaths.erase(it); + auto item = _pathToItemMap[path]; + + while (item) { + // During each iteration, delete item + QStandardItem* nextItem = nullptr; + + auto parent = item->parent(); + if (parent) { + parent->removeRow(item->row()); + if (parent->rowCount() > 0) { + // The parent still contains children, set the nextItem to null so we stop processing + nextItem = nullptr; + } else { + nextItem = parent; + } + } else { + removeRow(item->row()); + } + + _pathToItemMap.remove(path); + //delete item; + + item = nextItem; + } + //removeitem->index(); + } } else { - ++it; + emit errorGettingMappings(uint8_t(request->getError())); } - } + }); - for (auto& path : existingPaths) { - Q_ASSERT(_pathToItemMap.contains(path)); - qDebug() << "removing existing: " << path; - - auto item = _pathToItemMap[path]; - - while (item) { - // During each iteration, delete item - QStandardItem* nextItem = nullptr; - - auto parent = item->parent(); - if (parent) { - parent->removeRow(item->row()); - if (parent->rowCount() > 0) { - // The parent still contains children, set the nextItem to null so we stop processing - nextItem = nullptr; - } else { - nextItem = parent; - } - } else { - removeRow(item->row()); - } - - _pathToItemMap.remove(path); - //delete item; - - item = nextItem; - } - //removeitem->index(); - } - }); - - request->start(); + request->start(); + } else { + qDebug() << "NO CONNECTED ASSET SERVER"; + // not connected to an Asset Server, emit network error + emit errorGettingMappings(uint8_t(MappingRequest::NetworkError)); + } } diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 2d62f2d6e5..67c0856730 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -42,6 +42,9 @@ bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; + signals: + void errorGettingMappings(uint8_t error); + private: QHash _pathToItemMap; }; @@ -65,6 +68,7 @@ public: Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback); } Q_INVOKABLE void getAllMappings(QJSValue callback); Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback); + protected: QSet _pendingRequests; AssetMappingModel _assetMappingModel; diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index fb315434fd..e6a482ad27 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -34,7 +34,7 @@ void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { if (callback.isFunction()) { - QString url = "atp://" + hash; + QString url = "atp:" + hash; QScriptValueList args { url }; callback.call(_engine->currentContext()->thisObject(), args); } @@ -43,7 +43,7 @@ void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { } void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { - const QString ATP_SCHEME { "atp://" }; + const QString ATP_SCHEME { "atp:" }; if (!urlString.startsWith(ATP_SCHEME)) { return; From fccad7dca447d4b585c339c7d2993d663a336f3b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:24:11 -0800 Subject: [PATCH 121/258] remove nullptr request checks in AssetMappingsScriptingInterface --- .../src/AssetMappingsScriptingInterface.cpp | 98 +++++++------------ 1 file changed, 37 insertions(+), 61 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index fc21161f93..bccb57153a 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -51,95 +51,71 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback auto assetClient = DependencyManager::get(); auto request = assetClient->createGetMappingRequest(path); - if (request) { - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createDeleteMappingsRequest(paths); - if (request) { - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - if (request) { - connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto map = callback.engine()->newObject(); + connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto map = callback.engine()->newObject(); - for (auto& kv : mappings ) { - map.setProperty(kv.first, kv.second); - } + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } - QJSValueList args { uint8_t(request->getError()), map }; + QJSValueList args { uint8_t(request->getError()), map }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString newPath, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - if (request) { - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } From 9d19bf85b1c4a38fb128b2e3f4f0ea5ef0f243cb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:40:20 -0800 Subject: [PATCH 122/258] add consistent error handling for asset request and upload --- interface/src/assets/ATPAssetMigrator.cpp | 30 +++---- interface/src/ui/AssetUploadDialogFactory.cpp | 20 ++--- libraries/networking/src/AssetClient.cpp | 86 ++++++++++--------- .../networking/src/AssetResourceRequest.cpp | 8 -- libraries/networking/src/AssetUpload.cpp | 2 +- .../src/AssetScriptingInterface.cpp | 8 -- 6 files changed, 63 insertions(+), 91 deletions(-) diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index 51b2ac558a..e9327924a9 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -143,25 +143,17 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { QFileInfo assetInfo { request->getUrl().fileName() }; auto upload = assetClient->createUpload(request->getData()); - - if (upload) { - // add this URL to our hash of AssetUpload to original URL - _originalURLs.insert(upload, request->getUrl()); - - qCDebug(asset_migrator) << "Starting upload of asset from" << request->getUrl(); - - // connect to the finished signal so we know when the AssetUpload is done - QObject::connect(upload, &AssetUpload::finished, this, &ATPAssetMigrator::assetUploadFinished); - - // start the upload now - upload->start(); - } else { - // show a QMessageBox to say that there is no local asset server - QString messageBoxText = QString("Could not upload \n\n%1\n\nbecause you are currently not connected" \ - " to a local asset-server.").arg(assetInfo.fileName()); - - QMessageBox::information(_dialogParent, "Failed to Upload", messageBoxText); - } + + // add this URL to our hash of AssetUpload to original URL + _originalURLs.insert(upload, request->getUrl()); + + qCDebug(asset_migrator) << "Starting upload of asset from" << request->getUrl(); + + // connect to the finished signal so we know when the AssetUpload is done + QObject::connect(upload, &AssetUpload::finished, this, &ATPAssetMigrator::assetUploadFinished); + + // start the upload now + upload->start(); } void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& hash) { diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 46f07cb7df..7b2da4c83b 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -44,20 +44,12 @@ void AssetUploadDialogFactory::showDialog() { auto assetClient = DependencyManager::get(); auto upload = assetClient->createUpload(filename); - - if (upload) { - // connect to the finished signal so we know when the AssetUpload is done - QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); - - // start the upload now - upload->start(); - } else { - // show a QMessageBox to say that there is no local asset server - QString messageBoxText = QString("Could not upload \n\n%1\n\nbecause you are currently not connected" \ - " to a local asset-server.").arg(QFileInfo(filename).fileName()); - - QMessageBox::information(_dialogParent, "Failed to Upload", messageBoxText); - } + + // connect to the finished signal so we know when the AssetUpload is done + QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); + + // start the upload now + upload->start(); } } else { // we don't have permission to upload to asset server in this domain - show the permission denied error diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 79828cc235..8cb1f31090 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -144,62 +144,60 @@ GetMappingRequest* AssetClient::createGetMappingRequest(const AssetPath& path) { } GetAllMappingsRequest* AssetClient::createGetAllMappingsRequest() { - return new GetAllMappingsRequest(); + auto request = new GetAllMappingsRequest(); + + request->moveToThread(thread()); + + return request; } DeleteMappingsRequest* AssetClient::createDeleteMappingsRequest(const AssetPathList& paths) { - return new DeleteMappingsRequest(paths); + auto request = new DeleteMappingsRequest(paths); + + request->moveToThread(thread()); + + return request; } SetMappingRequest* AssetClient::createSetMappingRequest(const AssetPath& path, const AssetHash& hash) { - return new SetMappingRequest(path, hash); + auto request = new SetMappingRequest(path, hash); + + request->moveToThread(thread()); + + return request; } RenameMappingRequest* AssetClient::createRenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) { - return new RenameMappingRequest(oldPath, newPath); + auto request = new RenameMappingRequest(oldPath, newPath); + + request->moveToThread(thread()); + + return request; } AssetRequest* AssetClient::createRequest(const AssetHash& hash) { - if (isValidHash(hash)) { - qCWarning(asset_client) << "Invalid hash"; - return nullptr; - } + auto request = new AssetRequest(hash); - if (haveAssetServer()) { - auto request = new AssetRequest(hash); - - // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case) - request->moveToThread(thread()); - - return request; - } else { - return nullptr; - } + // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case) + request->moveToThread(thread()); + + return request; } AssetUpload* AssetClient::createUpload(const QString& filename) { - - if (haveAssetServer()) { - auto upload = new AssetUpload(filename); - - upload->moveToThread(thread()); - - return upload; - } else { - return nullptr; - } + auto upload = new AssetUpload(filename); + + upload->moveToThread(thread()); + + return upload; } AssetUpload* AssetClient::createUpload(const QByteArray& data) { - if (haveAssetServer()) { - auto upload = new AssetUpload(data); - - upload->moveToThread(thread()); - - return upload; - } else { - return nullptr; - } + auto upload = new AssetUpload(data); + + upload->moveToThread(thread()); + + return upload; } bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end, @@ -233,9 +231,12 @@ bool AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end _pendingRequests[assetServer][messageID] = { callback, progressCallback }; return true; + } else { + callback(false, AssetServerError::NoError, QByteArray()); + return false; } - return false; + } bool AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) { @@ -256,9 +257,10 @@ bool AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) { _pendingInfoRequests[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, { "", 0 }); + return false; } - - return false; } void AssetClient::handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode) { @@ -495,8 +497,10 @@ bool AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callb _pendingUploads[assetServer][messageID] = callback; return true; + } else { + callback(false, AssetServerError::NoError, QString()); + return false; } - return false; } void AssetClient::handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 3cc7bdd4c7..a896f94c8c 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -122,14 +122,6 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) { auto assetClient = DependencyManager::get(); _assetRequest = assetClient->createRequest(hash); - if (!_assetRequest) { - _result = ServerUnavailable; - _state = Finished; - - emit finished(); - return; - } - connect(_assetRequest, &AssetRequest::progress, this, &AssetResourceRequest::progress); connect(_assetRequest, &AssetRequest::finished, this, [this](AssetRequest* req) { Q_ASSERT(_state == InProgress); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 754d632cce..2840f6777c 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -41,7 +41,7 @@ QString AssetUpload::getErrorString() const { case AssetUpload::FileOpenError: return "The file could not be opened. Please check your permissions and try again."; case AssetUpload::NetworkError: - return "The file could not be opened. Please check your network connectivity."; + return "There was a problem reaching your Asset Server. Please check your network connectivity."; default: // not handled, do not show a message box return QString(); diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index e6a482ad27..aaa4f97fb3 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -27,10 +27,6 @@ AssetScriptingInterface::AssetScriptingInterface(QScriptEngine* engine) : void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { QByteArray dataByteArray = data.toUtf8(); auto upload = DependencyManager::get()->createUpload(dataByteArray); - if (!upload) { - qCWarning(asset_client) << "Error uploading file to asset server"; - return; - } QObject::connect(upload, &AssetUpload::finished, this, [this, callback](AssetUpload* upload, const QString& hash) mutable { if (callback.isFunction()) { @@ -61,10 +57,6 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb auto assetClient = DependencyManager::get(); auto assetRequest = assetClient->createRequest(hash); - if (!assetRequest) { - return; - } - _pendingRequests << assetRequest; connect(assetRequest, &AssetRequest::finished, this, [this, callback](AssetRequest* request) mutable { From 2bbeac6597f225f9d93bdaed9f1e103a67b87ea5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:42:45 -0800 Subject: [PATCH 123/258] short circuit asset request for invalid hash --- libraries/networking/src/AssetRequest.cpp | 9 +++++++++ libraries/networking/src/AssetRequest.h | 1 + libraries/networking/src/AssetResourceRequest.cpp | 12 +++--------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index f2e347e0f7..95812d5a52 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -35,6 +35,15 @@ void AssetRequest::start() { qCWarning(asset_client) << "AssetRequest already started."; return; } + + // in case we haven't parsed a valid hash, return an error now + if (isValidHash(_hash)) { + _result = InvalidHash; + _state = Finished; + + emit finished(this); + return; + } // Try to load from cache _data = loadFromCache(getUrl()); diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index ac4485a683..b98ac4ec4b 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -34,6 +34,7 @@ public: NoError, NotFound, InvalidByteRange, + InvalidHash, HashVerificationFailed, NetworkError, UnknownError diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index a896f94c8c..587eca6b0b 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -109,15 +109,6 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { void AssetResourceRequest::requestHash(const AssetHash& hash) { - // in case we haven't parsed a valid hash, return an error now - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - _result = InvalidURL; - _state = Finished; - - emit finished(); - return; - } - // Make request to atp auto assetClient = DependencyManager::get(); _assetRequest = assetClient->createRequest(hash); @@ -133,6 +124,9 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) { _data = req->getData(); _result = Success; break; + case AssetRequest::InvalidHash: + _result = InvalidURL; + break; case AssetRequest::Error::NotFound: _result = NotFound; break; From 9c53f40fbe30e6ad72194d613dc49216d2ed8ee3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 10:45:43 -0800 Subject: [PATCH 124/258] remove nullptr check in AssetMappingsScriptingInterface --- libraries/networking/src/AssetRequest.cpp | 2 +- .../src/AssetMappingsScriptingInterface.cpp | 174 +++++++++--------- 2 files changed, 85 insertions(+), 91 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 95812d5a52..93b1e4e698 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -38,7 +38,7 @@ void AssetRequest::start() { // in case we haven't parsed a valid hash, return an error now if (isValidHash(_hash)) { - _result = InvalidHash; + _error = InvalidHash; _state = Finished; emit finished(this); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index bccb57153a..95ceb3ce90 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -140,102 +140,96 @@ void AssetMappingModel::refresh() { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - if (request) { - connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { - if (request->getError() == MappingRequest::NoError) { - auto mappings = request->getMappings(); - auto existingPaths = _pathToItemMap.keys(); - for (auto& mapping : mappings) { - auto& path = mapping.first; - auto parts = path.split("/"); - auto length = parts.length(); + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + if (request->getError() == MappingRequest::NoError) { + auto mappings = request->getMappings(); + auto existingPaths = _pathToItemMap.keys(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); - existingPaths.removeOne(mapping.first); + existingPaths.removeOne(mapping.first); - QString fullPath = "/"; + QString fullPath = "/"; - QStandardItem* lastItem = nullptr; + QStandardItem* lastItem = nullptr; - // start index at 1 to avoid empty string from leading slash - for (int i = 1; i < length; ++i) { - fullPath += (i == 1 ? "" : "/") + parts[i]; + // start index at 1 to avoid empty string from leading slash + for (int i = 1; i < length; ++i) { + fullPath += (i == 1 ? "" : "/") + parts[i]; - auto it = _pathToItemMap.find(fullPath); - if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << fullPath; - auto item = new QStandardItem(parts[i]); - bool isFolder = i < length - 1; - item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); - item->setData(isFolder, Qt::UserRole + 1); - item->setData(parts[i], Qt::UserRole + 2); - item->setData("atp:" + fullPath, Qt::UserRole + 3); - if (lastItem) { - lastItem->setChild(lastItem->rowCount(), 0, item); - } else { - appendRow(item); - } - - lastItem = item; - _pathToItemMap[fullPath] = lastItem; - } - else { - lastItem = it.value(); - } - } - - Q_ASSERT(fullPath == path); - } - - // Remove folders from list - auto it = existingPaths.begin(); - while (it != existingPaths.end()) { - auto item = _pathToItemMap[*it]; - if (item->data(Qt::UserRole + 1).toBool()) { - it = existingPaths.erase(it); - } else { - ++it; - } - } - - for (auto& path : existingPaths) { - Q_ASSERT(_pathToItemMap.contains(path)); - qDebug() << "removing existing: " << path; - - auto item = _pathToItemMap[path]; - - while (item) { - // During each iteration, delete item - QStandardItem* nextItem = nullptr; - - auto parent = item->parent(); - if (parent) { - parent->removeRow(item->row()); - if (parent->rowCount() > 0) { - // The parent still contains children, set the nextItem to null so we stop processing - nextItem = nullptr; - } else { - nextItem = parent; - } + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + item->setData(isFolder, Qt::UserRole + 1); + item->setData(parts[i], Qt::UserRole + 2); + item->setData("atp:" + fullPath, Qt::UserRole + 3); + if (lastItem) { + lastItem->setChild(lastItem->rowCount(), 0, item); } else { - removeRow(item->row()); + appendRow(item); } - - _pathToItemMap.remove(path); - //delete item; - - item = nextItem; - } - //removeitem->index(); - } - } else { - emit errorGettingMappings(uint8_t(request->getError())); - } - }); - request->start(); - } else { - qDebug() << "NO CONNECTED ASSET SERVER"; - // not connected to an Asset Server, emit network error - emit errorGettingMappings(uint8_t(MappingRequest::NetworkError)); - } + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); + } + } + + Q_ASSERT(fullPath == path); + } + + // Remove folders from list + auto it = existingPaths.begin(); + while (it != existingPaths.end()) { + auto item = _pathToItemMap[*it]; + if (item->data(Qt::UserRole + 1).toBool()) { + it = existingPaths.erase(it); + } else { + ++it; + } + } + + for (auto& path : existingPaths) { + Q_ASSERT(_pathToItemMap.contains(path)); + qDebug() << "removing existing: " << path; + + auto item = _pathToItemMap[path]; + + while (item) { + // During each iteration, delete item + QStandardItem* nextItem = nullptr; + + auto parent = item->parent(); + if (parent) { + parent->removeRow(item->row()); + if (parent->rowCount() > 0) { + // The parent still contains children, set the nextItem to null so we stop processing + nextItem = nullptr; + } else { + nextItem = parent; + } + } else { + removeRow(item->row()); + } + + _pathToItemMap.remove(path); + //delete item; + + item = nextItem; + } + //removeitem->index(); + } + } else { + emit errorGettingMappings(uint8_t(request->getError())); + } + }); + + request->start(); } From 50a05df72162fa82087096edb2215a68551801af Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 11:58:55 -0800 Subject: [PATCH 125/258] fix asset loading with error changes --- assignment-client/src/assets/AssetServer.cpp | 2 +- libraries/networking/src/AssetRequest.cpp | 4 +-- .../networking/src/AssetResourceRequest.cpp | 36 ++++++++----------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 08cfa1252f..962e0fc583 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -482,7 +482,7 @@ void AssetServer::loadMappingsFromFile() { } } - qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment with not continue."; + qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment will not continue."; setFinished(true); } else { qInfo() << "No existing mappings loaded from file since no file was found at" << mapFilePath; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 93b1e4e698..e40b8d2cbe 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -37,7 +37,7 @@ void AssetRequest::start() { } // in case we haven't parsed a valid hash, return an error now - if (isValidHash(_hash)) { + if (!isValidHash(_hash)) { _error = InvalidHash; _state = Finished; @@ -62,7 +62,7 @@ void AssetRequest::start() { auto assetClient = DependencyManager::get(); assetClient->getAssetInfo(_hash, [this](bool responseReceived, AssetServerError serverError, AssetInfo info) { _info = info; - + if (!responseReceived) { _error = NetworkError; } else if (serverError != AssetServerError::NoError) { diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 587eca6b0b..c9063d7eae 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -58,15 +58,6 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { auto assetClient = DependencyManager::get(); _assetMappingRequest = assetClient->createGetMappingRequest(path); - // if we get a nullptr for createGetMappingRequest assume that there is no currently available asset-server - if (!_assetMappingRequest) { - _result = ServerUnavailable; - _state = Finished; - - emit finished(); - return; - } - // make sure we'll hear about the result of the get mapping request connect(_assetMappingRequest, &GetMappingRequest::finished, this, [this, path](GetMappingRequest* request){ Q_ASSERT(_state == InProgress); @@ -80,24 +71,27 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) { requestHash(request->getHash()); break; - case MappingRequest::NotFound: - // no result for the mapping request, set error to not found - _result = NotFound; + default: { + switch (request->getError()) { + case MappingRequest::NotFound: + // no result for the mapping request, set error to not found + _result = NotFound; + break; + case MappingRequest::NetworkError: + // didn't hear back from the server, mark it unavailable + _result = ServerUnavailable; + break; + default: + _result = Error; + break; + } // since we've failed we know we are finished _state = Finished; emit finished(); break; - default: - // these are unexpected errors for a GetMappingRequest object - _result = Error; - - // since we've failed we know we are finished - _state = Finished; - emit finished(); - - break; + } } _assetMappingRequest->deleteLater(); From e3cae5b026aa5292fb5cde4e77f2cc235786768b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 12:26:00 -0800 Subject: [PATCH 126/258] change setMapping for new disconnected error case --- .../src/AssetMappingsScriptingInterface.cpp | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index 95ceb3ce90..ee8deb4056 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -29,22 +29,16 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); - if (request) { - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; - callback.call(args); - - request->deleteLater(); - - }); - - request->start(); - } else { - // not connected to an Asset Server, return network error - QJSValueList args { uint8_t(MappingRequest::NetworkError) }; callback.call(args); - } + + request->deleteLater(); + + }); + + request->start(); } void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { From 273acc6a7e3a7f8097b62a46b7ceaa389d681e16 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 13:55:36 -0800 Subject: [PATCH 127/258] Add context menu to asset manager --- interface/resources/qml/AssetServer.qml | 71 ++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 0ce9cbee40..8db7d7b3dd 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -109,16 +109,22 @@ Window { Entities.addModelEntity(url, MyAvatar.position); } - function copyURLToClipboard() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x103); + function copyURLToClipboard(index) { + if (!index) { + index = treeView.currentIndex; + } + var path = assetMappingsModel.data(index, 0x103); if (!path) { return; } Window.copyToClipboard(path); } - function renameFile() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + function renameFile(index) { + if (!index) { + index = treeView.currentIndex; + } + var path = assetMappingsModel.data(index, 0x100); if (!path) { return; } @@ -141,8 +147,11 @@ Window { } }); } - function deleteFile() { - var path = assetMappingsModel.data(treeView.currentIndex, 0x100); + function deleteFile(index) { + if (!index) { + index = treeView.currentIndex; + } + var path = assetMappingsModel.data(index, 0x100); if (!path) { return; } @@ -271,6 +280,34 @@ Window { } } + Menu { + id: contextMenu + title: "Edit" + property var url: "" + property var currentIndex: null + + MenuItem { + text: "Copy URL" + onTriggered: { + copyURLToClipboard(contextMenu.currentIndex); + } + } + + MenuItem { + text: "Rename" + onTriggered: { + renameFile(contextMenu.currentIndex); + } + } + + MenuItem { + text: "Delete" + onTriggered: { + deleteFile(contextMenu.currentIndex); + } + } + } + HifiControls.Tree { id: treeView height: 400 @@ -278,6 +315,28 @@ Window { colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right + onClicked: { + print('here'); + } + rowDelegate: Rectangle { + height: hifi.dimensions.tableRowHeight + color: styleData.selected + ? hifi.colors.primaryHighlight + : treeView.isLightColorScheme + ? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd) + : (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd) + + } + MouseArea { + propagateComposedEvents: true + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + var index = treeView.indexAt(mouse.x, mouse.y); + contextMenu.currentIndex = index; + contextMenu.popup(); + } + } } } From 71bc937533e7320a53d1487e6f021265598ad0f2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 13:56:54 -0800 Subject: [PATCH 128/258] Remove copy URL button --- interface/resources/qml/AssetServer.qml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 8db7d7b3dd..df3612050b 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -235,16 +235,6 @@ Window { onClicked: root.reload() } - HifiControls.GlyphButton { - glyph: hifi.glyphs.reload - color: hifi.buttons.white - colorScheme: root.colorScheme - height: 26 - width: 26 - - onClicked: root.copyURLToClipboard() - } - HifiControls.Button { text: "ADD TO WORLD" color: hifi.buttons.white From ef8c66c1be201a959a54e5ff96e1d4fe5825f418 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 14:18:09 -0800 Subject: [PATCH 129/258] Remove commented out code --- interface/resources/qml/AssetServer.qml | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index df3612050b..d5a6a8b440 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -305,9 +305,6 @@ Window { colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right - onClicked: { - print('here'); - } rowDelegate: Rectangle { height: hifi.dimensions.tableRowHeight color: styleData.selected From c93ba2752b9f693fb408db525cb24567026de526 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 14:44:53 -0800 Subject: [PATCH 130/258] Remove rowDelegate styling for asset window --- interface/resources/qml/AssetServer.qml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 5f2eb6272a..c69af702fb 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -338,15 +338,6 @@ Window { colorScheme: root.colorScheme anchors.left: parent.left anchors.right: parent.right - rowDelegate: Rectangle { - height: hifi.dimensions.tableRowHeight - color: styleData.selected - ? hifi.colors.primaryHighlight - : treeView.isLightColorScheme - ? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd) - : (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd) - - } MouseArea { propagateComposedEvents: true anchors.fill: parent From 8cc0ae3148881697c8e37a9764129533b271b1a5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 13:16:02 -0800 Subject: [PATCH 131/258] menu and naming changes for asset server directory --- interface/resources/qml/AssetServer.qml | 2 +- interface/src/Menu.cpp | 11 ++++++----- interface/src/Menu.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c69af702fb..2f79eae931 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -21,7 +21,7 @@ import "dialogs" Window { id: root objectName: "AssetServer" - title: "Asset Server" + title: "My Asset Server" resizable: true destroyOnInvisible: true x: 40; y: 40 diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 58617bcb7c..abb1b4e143 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -95,10 +95,6 @@ Menu::Menu() { addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); - // Edit > Asset Server - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, - qApp, SLOT(toggleAssetServerWidget())); - // Edit > Open and Run Script from File... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, qApp, SLOT(loadDialog()), @@ -131,10 +127,15 @@ Menu::Menu() { SLOT(toggleConsole()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + editMenu->addSeparator(); + + // Edit > My Asset Server + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, qApp, SLOT(toggleAssetServerWidget())); + // Edit > Reload All Content [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - + // Edit > Package Model... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9ed7a605dc..93394828ec 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -34,7 +34,7 @@ namespace MenuOption { const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; const QString AssetMigration = "ATP Asset Migration"; - const QString AssetServer = "Asset Server"; + const QString AssetServer = "My Asset Server"; const QString Attachments = "Attachments..."; const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioNoiseReduction = "Audio Noise Reduction"; From 1678c9be20436bcd372f6b76388b214d7c208e30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 13:24:11 -0800 Subject: [PATCH 132/258] add a keyboard shortcut for the asset directory --- interface/src/Menu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index abb1b4e143..0724e75ea1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -130,7 +130,8 @@ Menu::Menu() { editMenu->addSeparator(); // Edit > My Asset Server - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, qApp, SLOT(toggleAssetServerWidget())); + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A, + qApp, SLOT(toggleAssetServerWidget())); // Edit > Reload All Content [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), From c65b5b63f0e50f31f353411cec9a544eec5317a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:20:16 -0800 Subject: [PATCH 133/258] better error handling for asset browser --- interface/resources/qml/AssetServer.qml | 30 +++++++------- .../src/AssetMappingsScriptingInterface.cpp | 39 +++++++++++++------ .../src/AssetMappingsScriptingInterface.h | 9 ++--- 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 2f79eae931..e74699f367 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -56,12 +56,13 @@ Window { Assets.deleteMappings(path, function(err) { if (err) { console.log("Error deleting path: ", path, err); - errorMessage("There was an error deleting:\n" + path + "\n\nPlease try again."); + + box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); } else { console.log("Finished deleting path: ", path); + reload(); } - - reload(); }); } @@ -76,7 +77,8 @@ Window { Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); - errorMessage("There was an error renaming:\n" + oldPath + " to " + newPath + "\n\nPlease try again."); + box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); } else { console.log("Finished rename: ", oldPath, "=>", newPath); } @@ -119,9 +121,11 @@ Window { Assets.mappingModel.refresh(); } - function handleGetMappingsError() { - errorMessage("There was a problem retreiving the list of assets from your Asset Server.\n" - + "Please make sure you are connected to the Asset Server and try again. "); + function handleGetMappingsError(errorCode) { + errorMessageBox( + "There was a problem retreiving the list of assets from your Asset Server.\n" + + Assets.getErrorString(errorCode) + ); } function addToWorld() { @@ -234,12 +238,12 @@ Window { }); } - function errorMessage(message) { - desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Error, - buttons: OriginalDialogs.StandardButton.Ok, - text: "Error", - informativeText: message + function errorMessageBox(message) { + return desktop.messageBox({ + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message }); } diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index ee8deb4056..e40e47b944 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -25,6 +25,27 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.sort(0); } +QString AssetMappingsScriptingInterface::getErrorString(int errorCode) const { + switch (errorCode) { + case MappingRequest::NoError: + return "No error"; + case MappingRequest::NotFound: + return "Asset not found"; + case MappingRequest::NetworkError: + return "Unable to communicate with Asset Server"; + case MappingRequest::PermissionDenied: + return "Permission denied"; + case MappingRequest::InvalidPath: + return "Path is invalid"; + case MappingRequest::InvalidHash: + return "Hash is invalid"; + case MappingRequest::UnknownError: + return "Asset Server internal error"; + default: + return QString(); + } +} + void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); @@ -113,22 +134,16 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new } -AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) - : name(name), +AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) : + name(name), fullPath(fullPath), - isFolder(isFolder) { + isFolder(isFolder) +{ } static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); -AssetMappingModel::AssetMappingModel() { -} - -AssetMappingModel::~AssetMappingModel() { - qDebug() << " DEST"; -} - void AssetMappingModel::refresh() { qDebug() << "Refreshing asset mapping model"; auto assetClient = DependencyManager::get(); @@ -221,7 +236,9 @@ void AssetMappingModel::refresh() { //removeitem->index(); } } else { - emit errorGettingMappings(uint8_t(request->getError())); + qDebug() << "THE ERROR IS" << request->getError(); + qDebug() << "Casted error is" << static_cast(request->getError()); + emit errorGettingMappings(static_cast(request->getError())); } }); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h index 67c0856730..3458da949a 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -33,17 +33,12 @@ class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: - AssetMappingModel(); - ~AssetMappingModel(); - -// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; - Q_INVOKABLE void refresh(); bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; signals: - void errorGettingMappings(uint8_t error); + void errorGettingMappings(int error); private: QHash _pathToItemMap; @@ -62,6 +57,8 @@ public: Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); }; + Q_INVOKABLE QString getErrorString(int errorCode) const; + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); Q_INVOKABLE void getMapping(QString path, QJSValue callback); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); From e93bc8317f039eb907512c9705cb67072303625a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:22:50 -0800 Subject: [PATCH 134/258] remove an extra space --- assignment-client/src/assets/AssetServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 962e0fc583..38f4c66f4b 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -464,7 +464,6 @@ void AssetServer::loadMappingsFromFile() { shouldDrop = true; } - if (!isValidHash(it.value().toString())) { qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a valid hash."; shouldDrop = true; From d077ade350087b64f67a1c0df07102bf8b15a9c5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:26:45 -0800 Subject: [PATCH 135/258] fix path regex to handle leading double slash --- libraries/networking/src/AssetUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 52ed7336c2..ac3d819ae2 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -31,7 +31,7 @@ const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB -const QString ASSET_PATH_REGEX_STRING = "^\\/(?:[^\\/]|\\/(?!\\/))*$"; +const QString ASSET_PATH_REGEX_STRING = "^\\/(?!\\/)(?:[^\\/]|\\/(?!\\/))*$"; const QString ASSET_HASH_REGEX_STRING = QString("^[a-fA-F0-9]{%1}$").arg(SHA256_HASH_HEX_LENGTH); enum AssetServerError : uint8_t { From 5167cf69b277ec8a425fa3ab1ca1e885a504b8d7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:41:35 -0800 Subject: [PATCH 136/258] fix for add to world and delete dialog --- interface/resources/qml/AssetServer.qml | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index e74699f367..97646de79f 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -129,7 +129,7 @@ Window { } function addToWorld() { - var url = assetMappingsModel.data(treeView.currentIndex, 0x102); + var url = assetProxyModel.data(treeView.currentIndex, 0x103); if (!url) { return; } @@ -137,15 +137,16 @@ Window { Entities.addModelEntity(url, MyAvatar.position); } - function copyURLToClipboard(index) { + function copyURLToClipboard() { if (!index) { index = treeView.currentIndex; } - var path = assetProxyModel.data(index, 0x103); - if (!path) { + + var url = assetProxyModel.data(treeView.currentIndex, 0x103); + if (!url) { return; } - Window.copyToClipboard(path); + Window.copyToClipboard(url); } function renameFile(index) { @@ -188,13 +189,11 @@ Window { var typeString = isFolder ? 'folder' : 'file'; var object = desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Question, - buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.No, - text: "Deleting", - informativeText: "You are about to delete the following " + typeString + ":\n" + - path + - "\nDo you want to continue?" + icon: hifi.icons.question, + buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.Yes, + title: "Delete", + text: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?" }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { From e227f68353675b2b9f7a6bb27c02d8e0aef9b6b8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:42:24 -0800 Subject: [PATCH 137/258] tweak wording for overwrite dialog --- interface/resources/qml/AssetServer.qml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 97646de79f..ade6563622 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -93,12 +93,11 @@ Window { function askForOverride(path, callback) { var object = desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Question, + icon: hifi.icons.question, buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.No, - text: "Override?", - informativeText: "The following file already exists:\n" + path + - "\nDo you want to override it?" + defaultButton: OriginalDialogs.StandardButton.Yes, + title: "Overwrite File", + text: path + "\n" + "This file already exists. Do you want to overwrite it?" }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { From 7f0917ea00f66d5f1d9727df65ebba7ca7973a51 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:47:24 -0800 Subject: [PATCH 138/258] add to world in front of MyAvatar --- interface/resources/qml/AssetServer.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index ade6563622..32e0a3b8ee 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -132,8 +132,8 @@ Window { if (!url) { return; } - - Entities.addModelEntity(url, MyAvatar.position); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); + Entities.addModelEntity(url, addPosition); } function copyURLToClipboard() { From b3d8b67893ed3696ed4ea88ef7e84ef962248644 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 14:50:21 -0800 Subject: [PATCH 139/258] remove committed debug lines --- libraries/script-engine/src/AssetMappingsScriptingInterface.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index e40e47b944..a843094df3 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -236,8 +236,6 @@ void AssetMappingModel::refresh() { //removeitem->index(); } } else { - qDebug() << "THE ERROR IS" << request->getError(); - qDebug() << "Casted error is" << static_cast(request->getError()); emit errorGettingMappings(static_cast(request->getError())); } }); From dc79d3262a979f268753fbb861377880e22bc1ba Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 9 Mar 2016 15:50:33 -0800 Subject: [PATCH 140/258] Update glyphs font --- .../qml/styles-uit/HifiConstants.qml | 131 +++++++++++++----- 1 file changed, 100 insertions(+), 31 deletions(-) diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 32cf61117b..09cba6d462 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -35,7 +35,7 @@ Item { glyph = hifi.glyphs.alert; break; case hifi.icons.critical: - glyph = hifi.glyphs.critical; + glyph = hifi.glyphs.error; break; case hifi.icons.placemark: glyph = hifi.glyphs.placemark; @@ -159,36 +159,6 @@ Item { readonly property real disclosureButton: dimensions.largeScreen ? 20 : 15 } - Item { - id: glyphs - readonly property string alert: "+" - readonly property string backward: "E" - readonly property string caratDn: "5" - readonly property string caratR: "3" - readonly property string caratUp: "6" - readonly property string close: "w" - readonly property string closeInverted: "x" - readonly property string closeSmall: "C" - readonly property string critical: "=" - readonly property string disclosureButtonCollapse: "M" - readonly property string disclosureButtonExpand: "L" - readonly property string disclosureCollapse: "Z" - readonly property string disclosureExpand: "B" - readonly property string forward: "D" - readonly property string info: "[" - readonly property string noIcon: "" - readonly property string pin: "y" - readonly property string pinInverted: "z" - readonly property string placemark: "U" - readonly property string question: "]" - readonly property string reloadSmall: "a" - readonly property string resizeHandle: "A" - readonly property string upload: "j" - readonly property string reload: "a" - readonly property string back: "1" - - } - Item { id: icons // Values per OffscreenUi::Icon @@ -221,4 +191,103 @@ Item { id: effects readonly property int fadeInDuration: 300 } + Item { + id: glyphs + readonly property string noIcon: "" + readonly property string hmd: "b" + readonly property string screen: "c" + readonly property string keyboard: "d" + readonly property string handControllers: "e" + readonly property string headphonesMic: "f" + readonly property string gamepad: "g" + readonly property string headphones: "h" + readonly property string mic: "i" + readonly property string upload: "j" + readonly property string script: "k" + readonly property string text: "l" + readonly property string cube: "m" + readonly property string sphere: "n" + readonly property string zone: "o" + readonly property string light: "p" + readonly property string web: "q" + readonly property string web2: "r" + readonly property string edit: "s" + readonly property string market: "t" + readonly property string directory: "u" + readonly property string menu: "v" + readonly property string close: "w" + readonly property string closeInverted: "x" + readonly property string pin: "y" + readonly property string pinInverted: "z" + readonly property string resizeHandle: "A" + readonly property string disclosureExpand: "B" + readonly property string reloadSmall: "a" + readonly property string closeSmall: "C" + readonly property string forward: "D" + readonly property string backward: "E" + readonly property string reload: "F" + readonly property string unmuted: "G" + readonly property string muted: "H" + readonly property string minimize: "I" + readonly property string maximize: "J" + readonly property string maximizeInverted: "K" + readonly property string disclosureButtonExpand: "L" + readonly property string disclosureButtonCollapse: "M" + readonly property string scriptStop: "N" + readonly property string scriptReload: "O" + readonly property string scriptRun: "P" + readonly property string scriptNew: "Q" + readonly property string hifiForum: "2" + readonly property string hifiLogoSmall: "S" + readonly property string avatar1: "T" + readonly property string placemark: "U" + readonly property string box: "V" + readonly property string community: "0" + readonly property string grabHandle: "X" + readonly property string search: "Y" + readonly property string disclosureCollapse: "Z" + readonly property string scriptUpload: "R" + readonly property string code: "W" + readonly property string avatar: "<" + readonly property string arrowsH: ":" + readonly property string arrowsV: ";" + readonly property string arrows: "`" + readonly property string compress: "!" + readonly property string expand: "\"" + readonly property string placemark1: "#" + readonly property string circle: "$" + readonly property string handPointer: "9" + readonly property string plusSquareO: "%" + readonly property string sliders: "&" + readonly property string square: "'" + readonly property string alignCenter: "8" + readonly property string alignJustify: ")" + readonly property string alignLeft: "*" + readonly property string alignRight: "^" + readonly property string bars: "7" + readonly property string circleSlash: "," + readonly property string sync: "()" + readonly property string key: "-" + readonly property string link: "." + readonly property string location: "/" + readonly property string caratR: "3" + readonly property string caratL: "4" + readonly property string caratDn: "5" + readonly property string caratUp: "6" + readonly property string folderLg: ">" + readonly property string folderSm: "?" + readonly property string levelUp: "1" + readonly property string info: "[" + readonly property string question: "]" + readonly property string alert: "+" + readonly property string home: "_" + readonly property string error: "=" + readonly property string settings: "@" + readonly property string trash: "{" + readonly property string objectGroup: "" + readonly property string cm: "}" + readonly property string msvg79: "~" + readonly property string deg: "\\" + readonly property string px: "|" + } } From 7d7a683b18ae9f623b8b379e2076f6ccfdcdaeb6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 13:33:36 -0800 Subject: [PATCH 141/258] Add uploadFile method that prompts the user --- interface/resources/qml/AssetServer.qml | 18 ++-- .../resources/qml/dialogs/QueryDialog.qml | 4 +- interface/src/Application.cpp | 2 +- .../AssetMappingsScriptingInterface.cpp | 84 ++++++++++++++----- .../AssetMappingsScriptingInterface.h | 1 + libraries/networking/src/MappingRequest.h | 1 + 6 files changed, 74 insertions(+), 36 deletions(-) rename {libraries/script-engine/src => interface/src/scripting}/AssetMappingsScriptingInterface.cpp (76%) rename {libraries/script-engine/src => interface/src/scripting}/AssetMappingsScriptingInterface.h (96%) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 32e0a3b8ee..eacbd15ec5 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -159,7 +159,7 @@ Window { var object = desktop.inputDialog({ label: "Enter new path:", - prefilledText: path, + current: path, placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { @@ -220,18 +220,12 @@ Window { var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); - var object = desktop.inputDialog({ - label: "Enter asset path:", - prefilledText: directory + filename, - placeholderText: "Enter path here" - }); - object.selected.connect(function(destinationPath) { - if (fileExists(destinationPath)) { - askForOverride(fileUrl, function() { - doUploadFile(fileUrl, destinationPath, addToWorld); - }); + Assets.uploadFile(fileUrl, directory + filename, function(err) { + if (err) { + console.log("Error uploading: ", fileUrl, " - error ", err); + errorMessage("There was an error uploading:\n" + fileUrl + "\n\nPlease try again."); } else { - doUploadFile(fileUrl, destinationPath, addToWorld); + console.log("Finished uploading: ", fileUrl); } }); } diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index 754851030c..48df9a41ce 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -34,12 +34,10 @@ ModalWindow { property var items; property string label property var result; - // FIXME not current honored - property var current; + property alias current: textResult.text // For text boxes property alias placeholderText: textResult.placeholderText - property alias prefilledText: textResult.text // For combo boxes property bool editable: true; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2660acfa00..e8b2384bbf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -66,7 +66,6 @@ #include #include #include -#include #include #include #include @@ -142,6 +141,7 @@ #include "ModelPackager.h" #include "PluginContainerProxy.h" #include "scripting/AccountScriptingInterface.h" +#include "scripting/AssetMappingsScriptingInterface.h" #include "scripting/AudioDeviceScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" #include "scripting/DesktopScriptingInterface.h" diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp similarity index 76% rename from libraries/script-engine/src/AssetMappingsScriptingInterface.cpp rename to interface/src/scripting/AssetMappingsScriptingInterface.cpp index a843094df3..b4f9458551 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -12,11 +12,13 @@ #include "AssetMappingsScriptingInterface.h" #include +#include #include #include #include #include +#include AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.setSourceModel(&_assetMappingModel); @@ -51,12 +53,12 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS auto request = assetClient->createSetMappingRequest(path, hash); connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -67,28 +69,70 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback auto request = assetClient->createGetMappingRequest(path); connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); } +void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { + QFile file(path); + if (!file.open(QFile::ReadOnly)) { + qCWarning(asset_client) << "Error uploading file to asset server:\n" + << "Could not open" << qPrintable(path); + OffscreenUi::warning("File Error", "Could not open file: " + path, QMessageBox::Ok); + return; + } + + auto offscreenUi = DependencyManager::get(); + auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); + if (!result.isValid()) { + return; + } + + // Check for override + if (isKnownMapping(result.toString())) { + auto message = "The following file already exists:\n" + path + "\nDo you want to override it?"; + auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "", message, + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (button == QMessageBox::No) { + return; + } + } + + auto upload = DependencyManager::get()->createUpload(file.readAll()); + QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { + if (upload->getError() != AssetUpload::NoError) { + if (callback.isCallable()) { + QJSValueList args { uint8_t(upload->getError()) }; + callback.call(args); + } + } else { + setMapping(mapping, hash, callback); + } + + upload->deleteLater(); + }); + + upload->start(); +} + void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createDeleteMappingsRequest(paths); connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -106,12 +150,12 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { map.setProperty(kv.first, kv.second); } - QJSValueList args { uint8_t(request->getError()), map }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -122,12 +166,12 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new auto request = assetClient->createRenameMappingRequest(oldPath, newPath); connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h similarity index 96% rename from libraries/script-engine/src/AssetMappingsScriptingInterface.h rename to interface/src/scripting/AssetMappingsScriptingInterface.h index 3458da949a..f1198ef17d 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -61,6 +61,7 @@ public: Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback); } Q_INVOKABLE void getAllMappings(QJSValue callback); diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h index c6a27e0274..504a0cb2fa 100644 --- a/libraries/networking/src/MappingRequest.h +++ b/libraries/networking/src/MappingRequest.h @@ -64,6 +64,7 @@ class SetMappingRequest : public MappingRequest { public: SetMappingRequest(const AssetPath& path, const AssetHash& hash); + AssetPath getPath() const { return _path; } AssetHash getHash() const { return _hash; } signals: From 548d826a4e58d6a95db92de16febec17a226706c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 14:04:52 -0800 Subject: [PATCH 142/258] Couple bug fixes --- interface/resources/qml/AssetServer.qml | 4 +++- interface/src/Application.cpp | 3 +-- .../scripting/AssetMappingsScriptingInterface.cpp | 15 ++++----------- .../scripting/AssetMappingsScriptingInterface.h | 2 +- libraries/networking/src/MappingRequest.cpp | 2 +- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index eacbd15ec5..1220f288f7 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -217,7 +217,7 @@ Window { var addToWorld = addToWorldCheckBox.checked var path = assetProxyModel.data(treeView.currentIndex, 0x100); - var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; + var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); Assets.uploadFile(fileUrl, directory + filename, function(err) { @@ -227,6 +227,8 @@ Window { } else { console.log("Finished uploading: ", fileUrl); } + + reload(); }); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e8b2384bbf..a8e64513ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -426,7 +426,6 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(true, qApp, qApp); DependencyManager::set(); @@ -1296,7 +1295,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Vec3", new Vec3()); rootContext->setContextProperty("Uuid", new ScriptUUID()); - rootContext->setContextProperty("Assets", DependencyManager::get().data()); + rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface()); rootContext->setContextProperty("AvatarList", DependencyManager::get().data()); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index b4f9458551..ea763210c9 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -81,22 +81,15 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback } void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { - QFile file(path); - if (!file.open(QFile::ReadOnly)) { - qCWarning(asset_client) << "Error uploading file to asset server:\n" - << "Could not open" << qPrintable(path); - OffscreenUi::warning("File Error", "Could not open file: " + path, QMessageBox::Ok); - return; - } - auto offscreenUi = DependencyManager::get(); auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); if (!result.isValid()) { return; } + mapping = result.toString(); // Check for override - if (isKnownMapping(result.toString())) { + if (isKnownMapping(mapping)) { auto message = "The following file already exists:\n" + path + "\nDo you want to override it?"; auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); @@ -105,7 +98,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, } } - auto upload = DependencyManager::get()->createUpload(file.readAll()); + auto upload = DependencyManager::get()->createUpload(path); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { if (callback.isCallable()) { @@ -242,7 +235,7 @@ void AssetMappingModel::refresh() { auto it = existingPaths.begin(); while (it != existingPaths.end()) { auto item = _pathToItemMap[*it]; - if (item->data(Qt::UserRole + 1).toBool()) { + if (item && item->data(Qt::UserRole + 1).toBool()) { it = existingPaths.erase(it); } else { ++it; diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index f1198ef17d..2ad7da7c94 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -45,7 +45,7 @@ }; -class AssetMappingsScriptingInterface : public QObject, public Dependency { +class AssetMappingsScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) Q_PROPERTY(QAbstractProxyModel* proxyModel READ getProxyModel CONSTANT) diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 6f76d1103f..2cc28c03be 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -109,7 +109,7 @@ void SetMappingRequest::doStart() { auto validPath = isValidPath(_path); auto validHash = isValidHash(_hash); if (!validPath || !validHash) { - _error = validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash; + _error = !validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash; emit finished(this); return; } From 63571a7c36d424dffa0157e67b3da2ea23d81787 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 14:57:02 -0800 Subject: [PATCH 143/258] Make sure Upload is not clicked several times --- interface/resources/qml/AssetServer.qml | 7 +++++++ .../src/scripting/AssetMappingsScriptingInterface.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 1220f288f7..0490db2fa7 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -212,7 +212,13 @@ Window { }); } + property var uploadOpen: false; function uploadClicked() { + if(uploadOpen) { + return; + } + uploadOpen = true; + var fileUrl = fileUrlTextField.text var addToWorld = addToWorldCheckBox.checked @@ -230,6 +236,7 @@ Window { reload(); }); + uploadOpen = false; } function errorMessageBox(message) { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index ea763210c9..9934b7937c 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -83,6 +83,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { auto offscreenUi = DependencyManager::get(); auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); + if (!result.isValid()) { return; } From cf12a8d3963439e83437b0c4dda4401836cd5013 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:02:19 -0800 Subject: [PATCH 144/258] always center the text in the message dialog --- interface/resources/qml/dialogs/MessageDialog.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index fa702090d3..4a25c51012 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -96,6 +96,7 @@ ModalWindow { } lineHeight: 2 lineHeightMode: Text.ProportionalHeight + horizontalAlignment: Text.AlignHCenter } RalewaySemiBold { From a6ccfb1685e75f77f6dfa3f39699cf44c83c6517 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 15:03:25 -0800 Subject: [PATCH 145/258] CR --- interface/resources/qml/AssetServer.qml | 2 +- .../src/scripting/AssetMappingsScriptingInterface.cpp | 4 ++-- .../src/scripting/AssetMappingsScriptingInterface.h | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 0490db2fa7..c4855b7704 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -214,7 +214,7 @@ Window { property var uploadOpen: false; function uploadClicked() { - if(uploadOpen) { + if (uploadOpen) { return; } uploadOpen = true; diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 9934b7937c..2839a0a9f6 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -91,8 +91,8 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, // Check for override if (isKnownMapping(mapping)) { - auto message = "The following file already exists:\n" + path + "\nDo you want to override it?"; - auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "", message, + auto message = path + "\n" + "This file already exists. Do you want to overwrite it?"; + auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (button == QMessageBox::No) { return; diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 2ad7da7c94..3a7711b340 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -59,13 +59,13 @@ public: Q_INVOKABLE QString getErrorString(int errorCode) const; - Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); - Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); + Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); - Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback); } - Q_INVOKABLE void getAllMappings(QJSValue callback); - Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback); + Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } + Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback = QJSValue()); protected: QSet _pendingRequests; From e29565a71701fba1521bf3775eef315e6f8d723d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:15:18 -0800 Subject: [PATCH 146/258] don't default to yes when prompted for overwrite --- interface/resources/qml/AssetServer.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c4855b7704..bcb236e7a1 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -91,11 +91,11 @@ Window { return Assets.isKnownMapping(path); } - function askForOverride(path, callback) { + function askForOverwrite(path, callback) { var object = desktop.messageBox({ icon: hifi.icons.question, buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.Yes, + defaultButton: OriginalDialogs.StandardButton.No, title: "Overwrite File", text: path + "\n" + "This file already exists. Do you want to overwrite it?" }); @@ -167,7 +167,7 @@ Window { return; } if (fileExists(destinationPath)) { - askForOverride(destinationPath, function() { + askForOverwrite(destinationPath, function() { doRenameFile(path, destinationPath); }); } else { @@ -229,7 +229,7 @@ Window { Assets.uploadFile(fileUrl, directory + filename, function(err) { if (err) { console.log("Error uploading: ", fileUrl, " - error ", err); - errorMessage("There was an error uploading:\n" + fileUrl + "\n\nPlease try again."); + errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); } else { console.log("Finished uploading: ", fileUrl); } From 76152906bea3c76281d63cf6cbb774a5f9d635b2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 15:37:38 -0800 Subject: [PATCH 147/258] Fix crash bug in asset manager --- .../src/AssetMappingsScriptingInterface.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp index ee8deb4056..77cc435fb8 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -155,13 +155,13 @@ void AssetMappingModel::refresh() { auto it = _pathToItemMap.find(fullPath); if (it == _pathToItemMap.end()) { - qDebug() << "prefix not found: " << fullPath; auto item = new QStandardItem(parts[i]); bool isFolder = i < length - 1; item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); item->setData(isFolder, Qt::UserRole + 1); item->setData(parts[i], Qt::UserRole + 2); item->setData("atp:" + fullPath, Qt::UserRole + 3); + item->setData(fullPath, Qt::UserRole + 4); if (lastItem) { lastItem->setChild(lastItem->rowCount(), 0, item); } else { @@ -182,6 +182,7 @@ void AssetMappingModel::refresh() { // Remove folders from list auto it = existingPaths.begin(); while (it != existingPaths.end()) { + Q_ASSERT(_pathToItemMap.contains(*it)); auto item = _pathToItemMap[*it]; if (item->data(Qt::UserRole + 1).toBool()) { it = existingPaths.erase(it); @@ -192,7 +193,6 @@ void AssetMappingModel::refresh() { for (auto& path : existingPaths) { Q_ASSERT(_pathToItemMap.contains(path)); - qDebug() << "removing existing: " << path; auto item = _pathToItemMap[path]; @@ -200,6 +200,7 @@ void AssetMappingModel::refresh() { // During each iteration, delete item QStandardItem* nextItem = nullptr; + auto fullPath = item->data(Qt::UserRole + 4).toString(); auto parent = item->parent(); if (parent) { parent->removeRow(item->row()); @@ -210,15 +211,15 @@ void AssetMappingModel::refresh() { nextItem = parent; } } else { - removeRow(item->row()); + auto removed = removeRow(item->row()); + Q_ASSERT(removed); } - _pathToItemMap.remove(path); - //delete item; + Q_ASSERT(_pathToItemMap.contains(fullPath)); + _pathToItemMap.remove(fullPath); item = nextItem; } - //removeitem->index(); } } else { emit errorGettingMappings(uint8_t(request->getError())); From 76ed16314a4f6b302def5b42d7f270ea37557e2c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 15:38:20 -0800 Subject: [PATCH 148/258] Add prepended slash on rename if missing --- interface/resources/qml/AssetServer.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c69af702fb..8819d1100c 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -73,6 +73,10 @@ Window { function doRenameFile(oldPath, newPath) { console.log("Renaming " + oldPath + " to " + newPath); + if (newPath[0] != "/") { + newPath = "/" + newPath; + } + Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); From ad0fb18d81dad2323d0a2b411132d581baf0ee0c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 10 Mar 2016 16:02:41 -0800 Subject: [PATCH 149/258] Add / to beginning of mapping on upload if missing --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 11a14c7686..6ac60ccbdf 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -88,6 +88,9 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, return; } mapping = result.toString(); + if (mapping[0] != '/') { + mapping = "/" + mapping; + } // Check for override if (isKnownMapping(mapping)) { From 35f5ebb93829885694e78de20677256a85d38d60 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 15:50:02 -0800 Subject: [PATCH 150/258] Don't allow folder overwrite --- interface/resources/qml/AssetServer.qml | 8 ++++++-- .../scripting/AssetMappingsScriptingInterface.cpp | 13 +++++++++++++ .../src/scripting/AssetMappingsScriptingInterface.h | 6 ++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index afb4b50773..768eaa28a2 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -72,12 +72,16 @@ Window { } function doRenameFile(oldPath, newPath) { - console.log("Renaming " + oldPath + " to " + newPath); - if (newPath[0] != "/") { newPath = "/" + newPath; } + if (Assets.isKnownFolder(newPath)) { + box = errorMessageBox("Cannot override existing directory."); + box.selected.connect(reload); + } + + console.log("Renaming " + oldPath + " to " + newPath); Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 6ac60ccbdf..ae2ef3183a 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -174,6 +174,19 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new request->start(); } +bool AssetMappingModel::isKnownFolder(QString path) const { + if (!path.endsWith("/")) { + return false; + } + + auto existingPaths = _pathToItemMap.keys(); + for (auto& entry : existingPaths) { + if (entry.startsWith(path)) { + return true; + } + } + return false; +} AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) : name(name), diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 3a7711b340..99ced25d29 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -35,7 +35,8 @@ public: Q_INVOKABLE void refresh(); - bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; + bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } + bool isKnownFolder(QString path) const; signals: void errorGettingMappings(int error); @@ -55,7 +56,8 @@ public: Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } Q_INVOKABLE QAbstractProxyModel* getProxyModel() { return &_proxyModel; } - Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); }; + Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); } + Q_INVOKABLE bool isKnownFolder(QString path) const { return _assetMappingModel.isKnownFolder(path); } Q_INVOKABLE QString getErrorString(int errorCode) const; From 16287b70407f87cf55d8b588cc435e5f43fe7a31 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 16:42:26 -0800 Subject: [PATCH 151/258] Disable add to world for uncompatible files --- interface/resources/qml/AssetServer.qml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 768eaa28a2..4cb69bb3ef 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -114,9 +114,8 @@ Window { }); } - function canAddToWorld() { + function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - var path = assetProxyModel.data(treeView.currentIndex, 0x100); return supportedExtensions.reduce(function(total, current) { return total | new RegExp(current).test(path); @@ -137,7 +136,7 @@ Window { function addToWorld() { var url = assetProxyModel.data(treeView.currentIndex, 0x103); - if (!url) { + if (!url || !canAddToWorld(url)) { return; } var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); @@ -288,7 +287,7 @@ Window { height: 26 width: 120 - enabled: canAddToWorld() + enabled: canAddToWorld(assetProxyModel.data(treeView.currentIndex, 0x100)) onClicked: root.addToWorld() } @@ -408,6 +407,9 @@ Window { anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x text: "Add to world on upload" + + enabled: canAddToWorld(fileUrlTextField.text) + checked: false } From 4a9d88d213c74b7f3b5465b852848a4b8536cd66 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Mar 2016 16:46:35 -0800 Subject: [PATCH 152/258] CR --- interface/resources/qml/AssetServer.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 4cb69bb3ef..a178374fed 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -77,7 +77,7 @@ Window { } if (Assets.isKnownFolder(newPath)) { - box = errorMessageBox("Cannot override existing directory."); + box = errorMessageBox("Cannot overwrite existing directory."); box.selected.connect(reload); } @@ -408,7 +408,7 @@ Window { text: "Add to world on upload" - enabled: canAddToWorld(fileUrlTextField.text) + opacity: canAddToWorld(fileUrlTextField.text) ? 1 : 0 checked: false } From 96a112290ffedd9a5ae9d0ba49f70c70be41e269 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:49:18 -0800 Subject: [PATCH 153/258] use mapping for overwrite prompt --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index ae2ef3183a..9d873409e0 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -94,7 +94,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, // Check for override if (isKnownMapping(mapping)) { - auto message = path + "\n" + "This file already exists. Do you want to overwrite it?"; + auto message = mapping + "\n" + "This file already exists. Do you want to overwrite it?"; auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (button == QMessageBox::No) { From ed4df72eed57f430c9707d630430b487f5a86904 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:50:09 -0800 Subject: [PATCH 154/258] cleanup logging for asset browser --- interface/resources/qml/AssetServer.qml | 46 +++++++++++++++---------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index a178374fed..9d4db830e2 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -55,23 +55,20 @@ Window { Assets.deleteMappings(path, function(err) { if (err) { - console.log("Error deleting path: ", path, err); + console.log("Asset browser - error deleting path: ", path, err); box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err)); box.selected.connect(reload); } else { - console.log("Finished deleting path: ", path); + console.log("Asset browser - finished deleting path: ", path); reload(); } }); } - function doUploadFile(path, mapping, addToWorld) { - console.log("Uploading " + path + " to " + mapping + " (addToWorld: " + addToWorld + ")"); - - } function doRenameFile(oldPath, newPath) { + if (newPath[0] != "/") { newPath = "/" + newPath; } @@ -81,14 +78,15 @@ Window { box.selected.connect(reload); } - console.log("Renaming " + oldPath + " to " + newPath); + console.log("Asset browser - renaming " + oldPath + " to " + newPath); + Assets.renameMapping(oldPath, newPath, function(err) { if (err) { - console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); + console.log("Asset browser - error renaming: ", oldPath, "=>", newPath, " - error ", err); box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err)); box.selected.connect(reload); } else { - console.log("Finished rename: ", oldPath, "=>", newPath); + console.log("Asset browser - finished rename: ", oldPath, "=>", newPath); } reload(); @@ -123,7 +121,6 @@ Window { } function reload() { - print("reload"); Assets.mappingModel.refresh(); } @@ -134,16 +131,22 @@ Window { ); } - function addToWorld() { - var url = assetProxyModel.data(treeView.currentIndex, 0x103); + function addToWorld(url) { + if (!url) { + url = assetProxyModel.data(treeView.currentIndex, 0x103); + } + if (!url || !canAddToWorld(url)) { return; } + + console.log("Asset browser - adding asset " + url + " to world."); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); Entities.addModelEntity(url, addPosition); } - function copyURLToClipboard() { + function copyURLToClipboard(index) { if (!index) { index = treeView.currentIndex; } @@ -227,7 +230,7 @@ Window { uploadOpen = true; var fileUrl = fileUrlTextField.text - var addToWorld = addToWorldCheckBox.checked + var shouldAddToWorld = addToWorldCheckBox.checked var path = assetProxyModel.data(treeView.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; @@ -235,13 +238,18 @@ Window { Assets.uploadFile(fileUrl, directory + filename, function(err) { if (err) { - console.log("Error uploading: ", fileUrl, " - error ", err); - errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); + var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); } else { - console.log("Finished uploading: ", fileUrl); - } + console.log("Asset Browser - finished uploading: ", fileUrl); - reload(); + if (shouldAddToWorld) { + addToWorld("atp:" + directory + filename); + } + + reload(); + } }); uploadOpen = false; } From 979fda7c8b49a14d55aacca78ca2fa78d3950305 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:53:05 -0800 Subject: [PATCH 155/258] add trimming for upload mapping --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 9d873409e0..603fd4dadd 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -88,6 +88,8 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, return; } mapping = result.toString(); + mapping = mapping.trimmed(); + if (mapping[0] != '/') { mapping = "/" + mapping; } From 52ee2499fc429ff832308edd969dd22af12aa7ca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 15:56:45 -0800 Subject: [PATCH 156/258] add trim prior to rename in AssetServer --- interface/resources/qml/AssetServer.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 9d4db830e2..a4421ac371 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -173,6 +173,8 @@ Window { placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { + destinationPath = destinationPath.trim(); + if (path == destinationPath) { return; } From e94e2ece2e0dd954b51fb2b426de747c9e5267cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 16:00:29 -0800 Subject: [PATCH 157/258] add trimming to paths on asset server --- assignment-client/src/assets/AssetServer.cpp | 12 +++++++++--- assignment-client/src/assets/AssetServer.h | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 38f4c66f4b..8598a33715 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -509,7 +509,8 @@ bool AssetServer::writeMappingsToFile() { return false; } -bool AssetServer::setMapping(const AssetPath& path, const AssetHash& hash) { +bool AssetServer::setMapping(AssetPath path, AssetHash hash) { + path = path.trimmed(); if (!isValidPath(path)) { qWarning() << "Cannot set a mapping for invalid path:" << path << "=>" << hash; @@ -555,7 +556,9 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { auto oldMappings = _fileMappings; // enumerate the paths to delete and remove them all - for (auto& path : paths) { + for (auto path : paths) { + + path = path.trimmed(); // figure out if this path will delete a file or folder if (pathIsFolder(path)) { @@ -602,7 +605,10 @@ bool AssetServer::deleteMappings(const AssetPathList& paths) { } } -bool AssetServer::renameMapping(const AssetPath& oldPath, const AssetPath& newPath) { +bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) { + oldPath = oldPath.trimmed(); + newPath = newPath.trimmed(); + if (!isValidPath(oldPath) || !isValidPath(newPath)) { qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:" << oldPath << "=>" << newPath; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 094ea58d41..2e4321e4cd 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -52,13 +52,13 @@ private: bool writeMappingsToFile(); /// Set the mapping for path to hash - bool setMapping(const AssetPath& path, const AssetHash& hash); + bool setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Returns `true` if deletion of mappings succeeds, else `false`. bool deleteMappings(const AssetPathList& paths); /// Rename mapping from `oldPath` to `newPath`. Returns true if successful - bool renameMapping(const AssetPath& oldPath, const AssetPath& newPath); + bool renameMapping(AssetPath oldPath, AssetPath newPath); void performMappingMigration(); From 6ae5ed6588f336c27c1818080e492e006a0aa965 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 16:04:10 -0800 Subject: [PATCH 158/258] add trimming to MappingRequest ctors --- libraries/networking/src/MappingRequest.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 2cc28c03be..7b675050a1 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -25,7 +25,7 @@ void MappingRequest::start() { doStart(); }; -GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path) { +GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path.trimmed()) { }; void GetMappingRequest::doStart() { @@ -97,7 +97,7 @@ void GetAllMappingsRequest::doStart() { }; SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& hash) : - _path(path), + _path(path.trimmed()), _hash(hash) { @@ -138,6 +138,9 @@ void SetMappingRequest::doStart() { }; DeleteMappingsRequest::DeleteMappingsRequest(const AssetPathList& paths) : _paths(paths) { + for (auto& path : _paths) { + path = path.trimmed(); + } }; void DeleteMappingsRequest::doStart() { @@ -175,8 +178,8 @@ void DeleteMappingsRequest::doStart() { }; RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const AssetPath& newPath) : - _oldPath(oldPath), - _newPath(newPath) + _oldPath(oldPath.trimmed()), + _newPath(newPath.trimmed()) { } From 6f550292f4b9efd9dfe866627eb6bf2489b5f0d9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 16:06:04 -0800 Subject: [PATCH 159/258] pass delete paths by reference for trimming --- assignment-client/src/assets/AssetServer.cpp | 4 ++-- assignment-client/src/assets/AssetServer.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 8598a33715..ff7d869a0b 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -551,12 +551,12 @@ bool pathIsFolder(const AssetPath& path) { return path.endsWith('/'); } -bool AssetServer::deleteMappings(const AssetPathList& paths) { +bool AssetServer::deleteMappings(AssetPathList& paths) { // take a copy of the current mappings in case persistence of these deletes fails auto oldMappings = _fileMappings; // enumerate the paths to delete and remove them all - for (auto path : paths) { + for (auto& path : paths) { path = path.trimmed(); diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 2e4321e4cd..1a8ebed50b 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -55,7 +55,7 @@ private: bool setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Returns `true` if deletion of mappings succeeds, else `false`. - bool deleteMappings(const AssetPathList& paths); + bool deleteMappings(AssetPathList& paths); /// Rename mapping from `oldPath` to `newPath`. Returns true if successful bool renameMapping(AssetPath oldPath, AssetPath newPath); From 625032f748bea7402abe80f70a6b32be6265dc9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 17:10:49 -0800 Subject: [PATCH 160/258] fix for add to world after upload name change --- interface/resources/qml/AssetServer.qml | 4 ++-- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index a4421ac371..a3fe6cacb8 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -238,7 +238,7 @@ Window { var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); - Assets.uploadFile(fileUrl, directory + filename, function(err) { + Assets.uploadFile(fileUrl, directory + filename, function(err, path) { if (err) { console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); @@ -247,7 +247,7 @@ Window { console.log("Asset Browser - finished uploading: ", fileUrl); if (shouldAddToWorld) { - addToWorld("atp:" + directory + filename); + addToWorld("atp:" + path); } reload(); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 603fd4dadd..32b697459c 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -54,7 +54,7 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { uint8_t(request->getError()), request->getPath() }; callback.call(args); } @@ -150,7 +150,7 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { } if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { uint8_t(request->getError()), map }; callback.call(args); } From 39e869fdfd0b4e26bef30c050489619c8a92cef6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 17:54:38 -0800 Subject: [PATCH 161/258] append a trailing slash for folder rename --- interface/resources/qml/AssetServer.qml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index a3fe6cacb8..e5e3d95a81 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -73,6 +73,11 @@ Window { newPath = "/" + newPath; } + if (oldPath[oldPath.length - 1] == '/' && newPath[newPath.length - 1] != '/') { + // this is a folder rename but the user neglected to add a trailing slash when providing a new path + newPath = newPath + "/"; + } + if (Assets.isKnownFolder(newPath)) { box = errorMessageBox("Cannot overwrite existing directory."); box.selected.connect(reload); From 8e2b06a8e5d59935fadb0ebd2b79a7fbbbb46e56 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 18:32:18 -0800 Subject: [PATCH 162/258] use an explicit selection model for treeview --- interface/resources/qml/AssetServer.qml | 18 ++++++++++-------- interface/resources/qml/controls-uit/Tree.qml | 4 ++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index e5e3d95a81..1a6247ced9 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -138,7 +138,7 @@ Window { function addToWorld(url) { if (!url) { - url = assetProxyModel.data(treeView.currentIndex, 0x103); + url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); } if (!url || !canAddToWorld(url)) { @@ -153,10 +153,10 @@ Window { function copyURLToClipboard(index) { if (!index) { - index = treeView.currentIndex; + index = treeView.selection.currentIndex; } - var url = assetProxyModel.data(treeView.currentIndex, 0x103); + var url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); if (!url) { return; } @@ -165,9 +165,11 @@ Window { function renameFile(index) { if (!index) { - index = treeView.currentIndex; + index = treeView.selection.currentIndex; } + console.log("THE CURRENT INDEX IS " + treeView.selection.currentIndex); var path = assetProxyModel.data(index, 0x100); + console.log("THE PATH IS " + path); if (!path) { return; } @@ -194,14 +196,14 @@ Window { } function deleteFile(index) { if (!index) { - index = treeView.currentIndex; + index = treeView.selection.currentIndex; } var path = assetProxyModel.data(index, 0x100); if (!path) { return; } - var isFolder = assetProxyModel.data(treeView.currentIndex, 0x101); + var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; var object = desktop.messageBox({ @@ -239,7 +241,7 @@ Window { var fileUrl = fileUrlTextField.text var shouldAddToWorld = addToWorldCheckBox.checked - var path = assetProxyModel.data(treeView.currentIndex, 0x100); + var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); @@ -302,7 +304,7 @@ Window { height: 26 width: 120 - enabled: canAddToWorld(assetProxyModel.data(treeView.currentIndex, 0x100)) + enabled: canAddToWorld(assetProxyModel.data(treeView.selection.currentIndex, 0x100)) onClicked: root.addToWorld() } diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index 18741d6420..a2572a2f5c 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -8,6 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +import QtQml.Models 2.2 import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -22,6 +23,9 @@ TreeView { readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light model: treeModel + selection: ItemSelectionModel { + model: treeModel + } TableViewColumn { role: "display"; From 7675c83f920ecb0505e7ece26255ff56261b9a19 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 18:34:28 -0800 Subject: [PATCH 163/258] clear selection on reload --- interface/resources/qml/AssetServer.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 1a6247ced9..db2f6dd83c 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -127,6 +127,7 @@ Window { function reload() { Assets.mappingModel.refresh(); + treeView.selection.clear(); } function handleGetMappingsError(errorCode) { From 7ccba8b40636425b5c0cc009476aed493eef872d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Mar 2016 18:36:12 -0800 Subject: [PATCH 164/258] remove debug for selected index crash --- interface/resources/qml/AssetServer.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index db2f6dd83c..c5ebb04819 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -168,9 +168,8 @@ Window { if (!index) { index = treeView.selection.currentIndex; } - console.log("THE CURRENT INDEX IS " + treeView.selection.currentIndex); + var path = assetProxyModel.data(index, 0x100); - console.log("THE PATH IS " + path); if (!path) { return; } From 631aad80f9b891739fe250767c74ba9d6b7979dc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 11 Mar 2016 09:53:08 -0800 Subject: [PATCH 165/258] Add Q_DECLARE_METATYPE(AssetMappingModel*) and fix indentation --- .../AssetMappingsScriptingInterface.h | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 99ced25d29..35a1c1ae7e 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -20,31 +20,32 @@ #include #include - class AssetMappingItem : public QStandardItem { - public: - AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); +class AssetMappingItem : public QStandardItem { +public: + AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); - QString name; - QString fullPath; - bool isFolder; - }; + QString name; + QString fullPath; + bool isFolder; +}; - class AssetMappingModel : public QStandardItemModel { - Q_OBJECT - public: - Q_INVOKABLE void refresh(); +class AssetMappingModel : public QStandardItemModel { + Q_OBJECT +public: + Q_INVOKABLE void refresh(); - bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } - bool isKnownFolder(QString path) const; + bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } + bool isKnownFolder(QString path) const; - signals: - void errorGettingMappings(int error); +signals: + void errorGettingMappings(int error); - private: - QHash _pathToItemMap; - }; +private: + QHash _pathToItemMap; +}; +Q_DECLARE_METATYPE(AssetMappingModel*); class AssetMappingsScriptingInterface : public QObject { Q_OBJECT From 9cdd0ac6d064820a5c4f59dccc327292143e204c Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 11 Mar 2016 10:19:44 -0800 Subject: [PATCH 166/258] Respect zone visibility property. --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 5cf1b1548a..180015b034 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -364,8 +364,9 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrsetBackgroundMode(model::SunSkyStage::SKY_BOX); + // Visibility does not effect other side effects such as ambient light or the selection of "best" zone. + // The skyStage backgroundMode is the hammer used (e.g., in Application.cpp) to control the visiblity of the sky box. + skyStage->setBackgroundMode(zone->getVisible() ? model::SunSkyStage::SKY_BOX : model::SunSkyStage::SKY_DOME); break; } From 9522c2d17cfe2c116b5c75246d791596fc364052 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 11:04:34 -0800 Subject: [PATCH 167/258] add file open and write error handling --- .../src/assets/UploadAssetTask.cpp | 21 ++++++++++++++----- libraries/networking/src/AssetUpload.cpp | 5 +++++ libraries/networking/src/AssetUpload.h | 3 ++- libraries/networking/src/AssetUtils.h | 3 ++- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index 0856a29e1f..e850f29991 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -61,13 +61,24 @@ void UploadAssetTask::run() { if (file.exists()) { qDebug() << "[WARNING] This file already exists: " << hexHash; - } else { - file.open(QIODevice::WriteOnly); - file.write(fileData); + + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(hash); + } else if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) { file.close(); + + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(hash); + } else { + // upload has failed - remove the file and return an error + auto removed = file.remove(); + + if (!removed) { + qWarning() << "Removal of failed upload file" << hash << "failed."; + } + + replyPacket->writePrimitive(AssetServerError::FileOperationFailed); } - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(hash); } auto nodeList = DependencyManager::get(); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 2840f6777c..44b7e9b681 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -42,6 +42,8 @@ QString AssetUpload::getErrorString() const { return "The file could not be opened. Please check your permissions and try again."; case AssetUpload::NetworkError: return "There was a problem reaching your Asset Server. Please check your network connectivity."; + case AssetUpload::ServerFileError: + return "The Asset Server failed to store the asset. Please try again."; default: // not handled, do not show a message box return QString(); @@ -90,6 +92,9 @@ void AssetUpload::start() { case AssetServerError::PermissionDenied: _error = PermissionDenied; break; + case AssetServerError::FileOperationFailed: + _error = ServerFileError; + break; default: _error = FileOpenError; break; diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h index 656c1a281e..82328ef2eb 100644 --- a/libraries/networking/src/AssetUpload.h +++ b/libraries/networking/src/AssetUpload.h @@ -32,7 +32,8 @@ public: Timeout, TooLarge, PermissionDenied, - FileOpenError + FileOpenError, + ServerFileError }; static const QString PERMISSION_DENIED_ERROR; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index ac3d819ae2..3a663af420 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -40,7 +40,8 @@ enum AssetServerError : uint8_t { InvalidByteRange, AssetTooLarge, PermissionDenied, - MappingOperationFailed + MappingOperationFailed, + FileOperationFailed }; enum AssetMappingOperationType : uint8_t { From e51aedeb35a7e99b2ff6a28c8bf649cf177ff4bf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 11:36:52 -0800 Subject: [PATCH 168/258] fix error handling for diff request types --- .../src/assets/UploadAssetTask.cpp | 5 ++- interface/resources/qml/AssetServer.qml | 12 +++---- .../AssetMappingsScriptingInterface.cpp | 35 ++++--------------- .../AssetMappingsScriptingInterface.h | 4 +-- libraries/networking/src/MappingRequest.cpp | 21 +++++++++++ libraries/networking/src/MappingRequest.h | 1 + 6 files changed, 40 insertions(+), 38 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index e850f29991..e82b99fe99 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -65,16 +65,19 @@ void UploadAssetTask::run() { replyPacket->writePrimitive(AssetServerError::NoError); replyPacket->write(hash); } else if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) { + qDebug() << "Wrote file" << hash << "to disk. Upload complete"; file.close(); replyPacket->writePrimitive(AssetServerError::NoError); replyPacket->write(hash); } else { + qWarning() << "Failed to upload or write to file" << hexHash << " - upload failed."; + // upload has failed - remove the file and return an error auto removed = file.remove(); if (!removed) { - qWarning() << "Removal of failed upload file" << hash << "failed."; + qWarning() << "Removal of failed upload file" << hexHash << "failed."; } replyPacket->writePrimitive(AssetServerError::FileOperationFailed); diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c5ebb04819..1be5867413 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -57,7 +57,7 @@ Window { if (err) { console.log("Asset browser - error deleting path: ", path, err); - box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err)); + box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err); box.selected.connect(reload); } else { console.log("Asset browser - finished deleting path: ", path); @@ -88,7 +88,7 @@ Window { Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Asset browser - error renaming: ", oldPath, "=>", newPath, " - error ", err); - box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err)); + box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + err); box.selected.connect(reload); } else { console.log("Asset browser - finished rename: ", oldPath, "=>", newPath); @@ -130,10 +130,10 @@ Window { treeView.selection.clear(); } - function handleGetMappingsError(errorCode) { + function handleGetMappingsError(errorString) { errorMessageBox( "There was a problem retreiving the list of assets from your Asset Server.\n" - + Assets.getErrorString(errorCode) + + errorString ); } @@ -168,7 +168,7 @@ Window { if (!index) { index = treeView.selection.currentIndex; } - + var path = assetProxyModel.data(index, 0x100); if (!path) { return; @@ -248,7 +248,7 @@ Window { Assets.uploadFile(fileUrl, directory + filename, function(err, path) { if (err) { console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); - var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + err); box.selected.connect(reload); } else { console.log("Asset Browser - finished uploading: ", fileUrl); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 32b697459c..d4f5431d32 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -27,34 +27,13 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.sort(0); } -QString AssetMappingsScriptingInterface::getErrorString(int errorCode) const { - switch (errorCode) { - case MappingRequest::NoError: - return "No error"; - case MappingRequest::NotFound: - return "Asset not found"; - case MappingRequest::NetworkError: - return "Unable to communicate with Asset Server"; - case MappingRequest::PermissionDenied: - return "Permission denied"; - case MappingRequest::InvalidPath: - return "Path is invalid"; - case MappingRequest::InvalidHash: - return "Hash is invalid"; - case MappingRequest::UnknownError: - return "Asset Server internal error"; - default: - return QString(); - } -} - void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()), request->getPath() }; + QJSValueList args { request->getErrorString(), request->getPath() }; callback.call(args); } @@ -70,7 +49,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { request->getErrorString() }; callback.call(args); } @@ -108,7 +87,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { if (callback.isCallable()) { - QJSValueList args { uint8_t(upload->getError()) }; + QJSValueList args { upload->getErrorString() }; callback.call(args); } } else { @@ -127,7 +106,7 @@ void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { request->getErrorString() }; callback.call(args); } @@ -150,7 +129,7 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { } if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()), map }; + QJSValueList args { request->getErrorString(), map }; callback.call(args); } @@ -166,7 +145,7 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { if (callback.isCallable()) { - QJSValueList args { uint8_t(request->getError()) }; + QJSValueList args { request->getErrorString() }; callback.call(args); } @@ -293,7 +272,7 @@ void AssetMappingModel::refresh() { } } } else { - emit errorGettingMappings(static_cast(request->getError())); + emit errorGettingMappings(request->getErrorString()); } }); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 99ced25d29..9a427a05ed 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -39,7 +39,7 @@ bool isKnownFolder(QString path) const; signals: - void errorGettingMappings(int error); + void errorGettingMappings(QString errorString); private: QHash _pathToItemMap; @@ -59,8 +59,6 @@ public: Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); } Q_INVOKABLE bool isKnownFolder(QString path) const { return _assetMappingModel.isKnownFolder(path); } - Q_INVOKABLE QString getErrorString(int errorCode) const; - Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 7b675050a1..be24c6b9d2 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -25,6 +25,27 @@ void MappingRequest::start() { doStart(); }; +QString MappingRequest::getErrorString() const { + switch (_error) { + case MappingRequest::NoError: + return "No error"; + case MappingRequest::NotFound: + return "Asset not found"; + case MappingRequest::NetworkError: + return "Unable to communicate with Asset Server"; + case MappingRequest::PermissionDenied: + return "Permission denied"; + case MappingRequest::InvalidPath: + return "Path is invalid"; + case MappingRequest::InvalidHash: + return "Hash is invalid"; + case MappingRequest::UnknownError: + return "Asset Server internal error"; + default: + return QString(); + } +} + GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path.trimmed()) { }; diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h index 504a0cb2fa..206e383c33 100644 --- a/libraries/networking/src/MappingRequest.h +++ b/libraries/networking/src/MappingRequest.h @@ -33,6 +33,7 @@ public: Q_INVOKABLE void start(); Error getError() const { return _error; } + Q_INVOKABLE QString getErrorString() const; protected: Error _error { NoError }; From 85e203e2cbec798f0f74ca99ded0afb924be4f4b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 11:44:46 -0800 Subject: [PATCH 169/258] return an empty string for no error --- libraries/networking/src/AssetUpload.cpp | 5 +++-- libraries/networking/src/MappingRequest.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 44b7e9b681..f99f5badb6 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -34,6 +34,8 @@ AssetUpload::AssetUpload(const QString& filename) : QString AssetUpload::getErrorString() const { // figure out the right error message for error switch (_error) { + case AssetUpload::NoError: + return QString(); case AssetUpload::PermissionDenied: return PERMISSION_DENIED_ERROR; case AssetUpload::TooLarge: @@ -45,8 +47,7 @@ QString AssetUpload::getErrorString() const { case AssetUpload::ServerFileError: return "The Asset Server failed to store the asset. Please try again."; default: - // not handled, do not show a message box - return QString(); + return QString("Unknown error with code %1").arg(_error); } } diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index be24c6b9d2..409957db42 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -28,7 +28,7 @@ void MappingRequest::start() { QString MappingRequest::getErrorString() const { switch (_error) { case MappingRequest::NoError: - return "No error"; + return QString(); case MappingRequest::NotFound: return "Asset not found"; case MappingRequest::NetworkError: @@ -42,7 +42,7 @@ QString MappingRequest::getErrorString() const { case MappingRequest::UnknownError: return "Asset Server internal error"; default: - return QString(); + return QString("Unknown error with code %1").arg(_error); } } From 7efe26e8543e4dcdff05f4ff650f1323d737b0f6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 11 Mar 2016 11:53:14 -0800 Subject: [PATCH 170/258] Disable asset browser if user can't rez --- interface/src/Menu.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0724e75ea1..dcec037c1c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -130,8 +130,12 @@ Menu::Menu() { editMenu->addSeparator(); // Edit > My Asset Server - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A, - qApp, SLOT(toggleAssetServerWidget())); + auto assetServerAction = addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, + Qt::CTRL | Qt::SHIFT | Qt::Key_A, + qApp, SLOT(toggleAssetServerWidget())); + auto nodeList = DependencyManager::get(); + QObject::connect(nodeList.data(), &NodeList::canRezChanged, assetServerAction, &QAction::setEnabled); + assetServerAction->setEnabled(nodeList->getThisNodeCanRez()); // Edit > Reload All Content [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), From f611d8f747f61347db4429ee8a84bc2b81b6cb70 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 12:41:18 -0800 Subject: [PATCH 171/258] if needed, set querryAACube when dimensions are updated --- .../src/RenderableModelEntityItem.cpp | 37 ++++++++++++++----- libraries/entities/src/EntityItem.cpp | 3 +- libraries/entities/src/EntityItem.h | 4 +- .../entities/src/EntityScriptingInterface.cpp | 6 ++- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 71b04d06a1..f3c205dadc 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -75,6 +75,23 @@ void RenderableModelEntityItem::loader() { void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { _dimensionsInitialized = true; ModelEntityItem::setDimensions(value); + + bool success; + AACube maxAACube = getMaximumAACube(success); + if (!success) { + return; + } + AACube queryAACube = getQueryAACube(success); + + if (!success || !queryAACube.contains(maxAACube)) { + EntityItemProperties properties; + properties.setQueryAACube(maxAACube); + qCDebug(entitiesrenderer) << "Auto-setting queryAACube:" << (!getName().isEmpty() ? getName() : getModelURL()); + QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", + Qt::QueuedConnection, + Q_ARG(QUuid, getEntityItemID()), + Q_ARG(EntityItemProperties, properties)); + } } bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties) { @@ -512,15 +529,17 @@ bool RenderableModelEntityItem::needsToCallUpdate() const { void RenderableModelEntityItem::update(const quint64& now) { if (!_dimensionsInitialized && _model && _model->isActive()) { - EntityItemProperties properties; - auto extents = _model->getMeshExtents(); - properties.setDimensions(extents.maximum - extents.minimum); - - qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL()); - QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", - Qt::QueuedConnection, - Q_ARG(QUuid, getEntityItemID()), - Q_ARG(EntityItemProperties, properties)); + const QSharedPointer renderNetworkGeometry = _model->getGeometry(); + if (renderNetworkGeometry && renderNetworkGeometry->isLoaded()) { + EntityItemProperties properties; + auto extents = _model->getMeshExtents(); + properties.setDimensions(extents.maximum - extents.minimum); + qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL()); + QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", + Qt::QueuedConnection, + Q_ARG(QUuid, getEntityItemID()), + Q_ARG(EntityItemProperties, properties)); + } } ModelEntityItem::update(now); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3c918a0a77..8f6d497461 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1307,8 +1307,7 @@ AACube EntityItem::getQueryAACube(bool& success) const { // this is for when we've loaded an older json file that didn't have queryAACube properties. result = getMaximumAACube(success); if (success) { - _queryAACube = result; - _queryAACubeSet = true; + getThisPointer()->setQueryAACube(result); } return result; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5bd761b4e3..577bb406bc 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -75,7 +75,9 @@ public: EntityItem(const EntityItemID& entityItemID); virtual ~EntityItem(); - inline EntityItemPointer getThisPointer() { return std::static_pointer_cast(shared_from_this()); } + inline EntityItemPointer getThisPointer() const { + return std::static_pointer_cast(std::const_pointer_cast(shared_from_this())); + } EntityItemID getEntityItemID() const { return EntityItemID(_id); } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 702b1ed916..c195d12ca3 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -148,7 +148,11 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties if (entity) { if (propertiesWithSimID.parentRelatedPropertyChanged()) { // due to parenting, the server may not know where something is in world-space, so include the bounding cube. - propertiesWithSimID.setQueryAACube(entity->getQueryAACube()); + bool success; + AACube queryAACube = entity->getQueryAACube(success); + if (success) { + propertiesWithSimID.setQueryAACube(queryAACube); + } } if (_bidOnSimulationOwnership) { From 7a4dad8e51a1d04a33325de537c7485baea0ab4e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 13:20:52 -0800 Subject: [PATCH 172/258] allow entity-server to patch up broken queryAACubes --- libraries/entities/src/EntityItem.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8f6d497461..15d358475f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1300,16 +1300,22 @@ AABox EntityItem::getAABox(bool& success) const { } AACube EntityItem::getQueryAACube(bool& success) const { - AACube result = SpatiallyNestable::getQueryAACube(success); + AACube queryAACube = SpatiallyNestable::getQueryAACube(success); + bool maxAACubeSuccess; + AACube maxAACube = getMaximumAACube(maxAACubeSuccess); if (success) { - return result; + // allow server to patch up broken queryAACubes + if (maxAACubeSuccess && !queryAACube.contains(maxAACube)) { + getThisPointer()->setQueryAACube(maxAACube); + } + return _queryAACube; } // this is for when we've loaded an older json file that didn't have queryAACube properties. - result = getMaximumAACube(success); - if (success) { - getThisPointer()->setQueryAACube(result); + success = maxAACubeSuccess; + if (maxAACubeSuccess) { + getThisPointer()->setQueryAACube(maxAACube); } - return result; + return _queryAACube; } From 630f5303b2f8ac660d2ef4dd8f662d4f9bd8622f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 13:23:57 -0800 Subject: [PATCH 173/258] overwrite existing asset during upload if hash doesn't match --- .../src/assets/UploadAssetTask.cpp | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index e82b99fe99..5ca9b5bbf1 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -58,30 +58,46 @@ void UploadAssetTask::run() { << "is: (" << hexHash << ") "; QFile file { _resourcesDir.filePath(QString(hexHash)) }; + + bool existingCorrectFile = false; if (file.exists()) { - qDebug() << "[WARNING] This file already exists: " << hexHash; + // check if the local file has the correct contents, otherwise we overwrite + if (file.open(QIODevice::ReadOnly) && hashData(file.readAll()) == hash) { + qDebug() << "Not overwriting existing verified file: " << hexHash; - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(hash); - } else if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) { - qDebug() << "Wrote file" << hash << "to disk. Upload complete"; - file.close(); + existingCorrectFile = true; - replyPacket->writePrimitive(AssetServerError::NoError); - replyPacket->write(hash); - } else { - qWarning() << "Failed to upload or write to file" << hexHash << " - upload failed."; - - // upload has failed - remove the file and return an error - auto removed = file.remove(); - - if (!removed) { - qWarning() << "Removal of failed upload file" << hexHash << "failed."; + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(hash); + } else { + qDebug() << "Overwriting an existing file whose contents did not match the expected hash: " << hexHash; + file.close(); } - - replyPacket->writePrimitive(AssetServerError::FileOperationFailed); } + + if (!existingCorrectFile) { + if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) { + qDebug() << "Wrote file" << hexHash << "to disk. Upload complete"; + file.close(); + + replyPacket->writePrimitive(AssetServerError::NoError); + replyPacket->write(hash); + } else { + qWarning() << "Failed to upload or write to file" << hexHash << " - upload failed."; + + // upload has failed - remove the file and return an error + auto removed = file.remove(); + + if (!removed) { + qWarning() << "Removal of failed upload file" << hexHash << "failed."; + } + + replyPacket->writePrimitive(AssetServerError::FileOperationFailed); + } + } + + } auto nodeList = DependencyManager::get(); From d7b800283b926dd535396760157d42e6bb86df24 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 11 Mar 2016 13:57:05 -0800 Subject: [PATCH 174/258] Adjust bugsplat to use qPrintable --- interface/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 3a4807ad6a..5a53fdd4bf 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -39,7 +39,7 @@ int main(int argc, const char* argv[]) { static const DWORD BUG_SPLAT_FLAGS = MDSF_PREVENTHIJACKING | MDSF_USEGUARDMEMORY; static const char* BUG_SPLAT_DATABASE = "interface_alpha"; static const char* BUG_SPLAT_APPLICATION_NAME = "Interface"; - MiniDmpSender mpSender { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, BuildInfo::VERSION.toLatin1().constData(), + MiniDmpSender mpSender { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, qPrintable(BuildInfo::VERSION), nullptr, BUG_SPLAT_FLAGS }; #endif @@ -145,9 +145,9 @@ int main(int argc, const char* argv[]) { #ifdef HAS_BUGSPLAT AccountManager& accountManager = AccountManager::getInstance(); - mpSender.setDefaultUserName(accountManager.getAccountInfo().getUsername().toLatin1().constData()); + mpSender.setDefaultUserName(qPrintable(accountManager.getAccountInfo().getUsername())); QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&mpSender](const QString& newUsername) { - mpSender.setDefaultUserName(newUsername.toLatin1().constData()); + mpSender.setDefaultUserName(qPrintable(newUsername)); }); #endif From ee1fb698a4656b7b22fb87b5a9d79a8f26a7428a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 8 Mar 2016 12:50:21 -0800 Subject: [PATCH 175/258] Add texture transparency to material key --- libraries/model/src/model/Material.cpp | 7 +++--- libraries/model/src/model/Material.h | 12 ++++++++-- libraries/model/src/model/Material.slh | 24 +++++++++---------- .../render-utils/src/MeshPartPayload.cpp | 9 +++---- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 10fa15edd5..306867c204 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -80,6 +80,10 @@ void Material::setMetallic(float metallic) { _schemaBuffer.edit()._metallic = metallic; } +void Material::setTransparentTexture(bool isTransparent) { + _key.setTransparentTexture(isTransparent); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); +} void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { if (textureMap) { @@ -92,6 +96,3 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur _textureMaps.erase(channel); } } - - - diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index b22f8a3f42..078fc6499a 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -32,6 +32,7 @@ public: METALLIC_VAL_BIT, GLOSSY_VAL_BIT, TRANSPARENT_VAL_BIT, + TRANSPARENT_TEX_VAL_BIT, EMISSIVE_MAP_BIT, ALBEDO_MAP_BIT, @@ -101,6 +102,9 @@ public: void setAlbedo(bool value) { _flags.set(ALBEDO_VAL_BIT, value); } bool isAlbedo() const { return _flags[ALBEDO_VAL_BIT]; } + void setTransparentTexture(bool value) { _flags.set(TRANSPARENT_TEX_VAL_BIT, value); } + bool isTransparentTexture() const { return _flags[TRANSPARENT_TEX_VAL_BIT]; } + void setAlbedoMap(bool value) { _flags.set(ALBEDO_MAP_BIT, value); } bool isAlbedoMap() const { return _flags[ALBEDO_MAP_BIT]; } @@ -164,6 +168,9 @@ public: Builder& withoutAlbedo() { _value.reset(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } Builder& withAlbedo() { _value.set(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } + Builder& withoutTransparentTexture() { _value.reset(MaterialKey::TRANSPARENT_TEX_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); return (*this); } + Builder& withTransparentTexture() { _value.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); return (*this); } + Builder& withoutAlbedoMap() { _value.reset(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } Builder& withAlbedoMap() { _value.set(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } @@ -248,6 +255,8 @@ public: void setRoughness(float roughness); float getRoughness() const { return _schemaBuffer.get()._roughness; } + void setTransparentTexture(bool isTransparent); + // Schema to access the attribute values of the material class Schema { public: @@ -260,8 +269,7 @@ public: glm::vec3 _fresnel{ 0.03f }; // Fresnel value for a default non metallic float _metallic{ 0.0f }; // Not Metallic - - glm::vec3 _spare0{ 0.0f }; + glm::vec3 _spare{ 0.0f }; uint32_t _key{ 0 }; // a copy of the materialKey diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index d75f3df5e0..da185ddf0b 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -15,7 +15,7 @@ struct Material { vec4 _emissiveOpacity; vec4 _albedoRoughness; vec4 _fresnelMetallic; - vec4 _spare; + vec4 _spareKey; }; uniform materialBuffer { @@ -37,25 +37,23 @@ float getMaterialMetallic(Material m) { return m._fresnelMetallic.a; } float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); } -int getMaterialKey(Material m) { return floatBitsToInt(m._spare.w); } +int getMaterialKey(Material m) { return floatBitsToInt(m._spareKey.w); } const int EMISSIVE_VAL_BIT = 0x00000001; const int ALBEDO_VAL_BIT = 0x00000002; const int METALLIC_VAL_BIT = 0x00000004; const int GLOSSY_VAL_BIT = 0x00000008; const int TRANSPARENT_VAL_BIT = 0x00000010; +const int TRANSPARENT_TEX_VAL_BIT = 0x00000020; +const int EMISSIVE_MAP_BIT = 0x00000040; +const int ALBEDO_MAP_BIT = 0x00000080; +const int METALLIC_MAP_BIT = 0x00000100; +const int ROUGHNESS_MAP_BIT = 0x00000200; +const int TRANSPARENT_MAP_BIT = 0x00000400; +const int NORMAL_MAP_BIT = 0x00000800; +const int OCCLUSION_MAP_BIT = 0x00001000; -const int EMISSIVE_MAP_BIT = 0x00000020; -const int ALBEDO_MAP_BIT = 0x00000040; -const int METALLIC_MAP_BIT = 0x00000080; -const int ROUGHNESS_MAP_BIT = 0x00000100; -const int TRANSPARENT_MAP_BIT = 0x00000200; -const int NORMAL_MAP_BIT = 0x00000400; -const int OCCLUSION_MAP_BIT = 0x00000800; - -const int LIGHTMAP_MAP_BIT = 0x00001000; - - +const int LIGHTMAP_MAP_BIT = 0x00002000; <@endif@> diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 166b14333f..4ae5b4532a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -81,7 +81,7 @@ ItemKey MeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { + if (matKey.isTransparent() || matKey.isTransparentTexture() || matKey.isTransparentMap()) { builder.withTransparent(); } } @@ -100,7 +100,7 @@ ShapeKey MeshPartPayload::getShapeKey() const { } ShapeKey::Builder builder; - if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap()) { + if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentTexture() || drawMaterialKey.isTransparentMap()) { builder.withTranslucent(); } if (drawMaterialKey.isNormalMap()) { @@ -365,7 +365,7 @@ ItemKey ModelMeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { + if (matKey.isTransparent() || matKey.isTransparentTexture() || matKey.isTransparentMap()) { builder.withTransparent(); } } @@ -412,7 +412,8 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { drawMaterialKey = _drawMaterial->getKey(); } - bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); + bool isTranslucent = + drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentTexture() || drawMaterialKey.isTransparentMap(); bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); From 22d41c833f8b8b7bde69994ebd521b48badc48dd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 29 Feb 2016 19:26:18 -0800 Subject: [PATCH 176/258] Update loaded models with texture transparency --- .../model-networking/src/model-networking/ModelCache.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 21eed5f59f..29c517594a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -145,7 +145,13 @@ bool NetworkGeometry::isLoadedWithTextures() const { (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } + if (material->albedoTexture) { + // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent + const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); + material->_material->setTransparentTexture(usage.isAlpha() && !usage.isAlphaMask()); + } } + _isLoadedWithTextures = true; } return true; From 3b62e203f754717c49ea256c425642801d251759 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 11 Mar 2016 14:25:21 -0800 Subject: [PATCH 177/258] Cache NetworkGeometry::_hasTransparentTextures --- .../model-networking/src/model-networking/ModelCache.cpp | 6 +++++- .../model-networking/src/model-networking/ModelCache.h | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 29c517594a..af9fe97e93 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -135,6 +135,8 @@ bool NetworkGeometry::isLoadedWithTextures() const { } if (!_isLoadedWithTextures) { + _hasTransparentTextures = false; + for (auto&& material : _materials) { if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || (material->normalTexture && !material->normalTexture->isLoaded()) || @@ -148,7 +150,9 @@ bool NetworkGeometry::isLoadedWithTextures() const { if (material->albedoTexture) { // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); - material->_material->setTransparentTexture(usage.isAlpha() && !usage.isAlphaMask()); + bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); + material->_material->setTransparentTexture(isTransparentTexture); + _hasTransparentTextures = _hasTransparentTextures || isTransparentTexture; } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 60f185f691..7f01bdafaa 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -75,6 +75,10 @@ public: // true when the requested geometry and its textures are loaded. bool isLoadedWithTextures() const; + // true if the albedo texture has a non-masking alpha channel. + // This can only be known after isLoadedWithTextures(). + bool hasTransparentTextures() const { return _hasTransparentTextures; } + // WARNING: only valid when isLoaded returns true. const FBXGeometry& getFBXGeometry() const { return *_geometry; } const std::vector>& getMeshes() const { return _meshes; } @@ -151,6 +155,7 @@ protected: // cache for isLoadedWithTextures() mutable bool _isLoadedWithTextures = false; + mutable bool _hasTransparentTextures = false; }; /// Reads geometry in a worker thread. From a89a76dc4b8034833bea89fa6c011ffd91eb62bd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 11 Mar 2016 14:25:39 -0800 Subject: [PATCH 178/258] Require model fixup if tex is transparent --- libraries/render-utils/src/Model.cpp | 17 +++++++++++++++++ libraries/render-utils/src/Model.h | 12 +++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ce6dfd6849..8b6cc41f35 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -74,6 +74,21 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; +bool Model::needsFixupInScene() { + if (readyToAddToScene()) { + // Once textures are loaded, fixup if they are now transparent + if (!_needsReload && _needsUpdateTransparentTextures && _geometry->isLoadedWithTextures()) { + _needsUpdateTransparentTextures = false; + if (_hasTransparentTextures != _geometry->hasTransparentTextures()) { + return true; + } + } + if (!_readyWhenAdded) { + return true; + } + } + return false; +} void Model::setTranslation(const glm::vec3& translation) { _translation = translation; @@ -728,6 +743,8 @@ void Model::setURL(const QUrl& url) { } _needsReload = true; + _needsUpdateTransparentTextures = true; + _hasTransparentTextures = false; _meshGroupsKnown = false; invalidCalculatedMeshBoxes(); deleteGeometry(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 424eed1e66..e90d51813b 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -70,7 +70,7 @@ public: // new Scene/Engine rendering support void setVisibleInScene(bool newValue, std::shared_ptr scene); - bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); } + bool needsFixupInScene(); bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return !_needsReload && isRenderable() && isActive() && isLoaded(); } @@ -365,10 +365,12 @@ protected: QSet> _renderItemsSet; QMap _renderItems; - bool _readyWhenAdded = false; - bool _needsReload = true; - bool _needsUpdateClusterMatrices = true; - bool _showCollisionHull = false; + bool _readyWhenAdded { false }; + bool _needsReload { true }; + bool _needsUpdateClusterMatrices { true }; + bool _needsUpdateTransparentTextures { true }; + bool _hasTransparentTextures { false }; + bool _showCollisionHull { false }; friend class ModelMeshPartPayload; RigPointer _rig; From 2ad15f75682ea97dc98f08a09fe6b40b7438d517 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 14:38:31 -0800 Subject: [PATCH 179/258] try harder to get queryAABoxes to be correct --- .../src/RenderableModelEntityItem.cpp | 6 ++- libraries/entities/src/EntityItem.cpp | 44 ++++++++++--------- libraries/entities/src/EntityItem.h | 7 +-- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f3c205dadc..2734d968a9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -74,14 +74,16 @@ void RenderableModelEntityItem::loader() { void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { _dimensionsInitialized = true; - ModelEntityItem::setDimensions(value); bool success; + AACube queryAACube = getQueryAACube(success); + + ModelEntityItem::setDimensions(value); + AACube maxAACube = getMaximumAACube(success); if (!success) { return; } - AACube queryAACube = getQueryAACube(success); if (!success || !queryAACube.contains(maxAACube)) { EntityItemProperties properties; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 15d358475f..71be12682b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1202,11 +1202,35 @@ const Transform EntityItem::getTransformToCenter(bool& success) const { return result; } +void EntityItem::checkAndAdjustQueryAACube() { + bool maxAACubeSuccess; + AACube maxAACube = getMaximumAACube(maxAACubeSuccess); + if (maxAACubeSuccess) { + if (!_queryAACubeSet || !_queryAACube.contains(maxAACube)) { + // allow server to patch up broken queryAACubes + EntityTreePointer tree = getTree(); + if (tree) { + qDebug() << "EntityItem::checkAndAdjustQueryAACube" << getName(); + EntityItemProperties properties; + properties.setQueryAACube(maxAACube); + tree->updateEntity(getID(), properties); + } + } + } +} + +void EntityItem::setParentID(const QUuid& parentID) { + SpatiallyNestable::setParentID(parentID); + checkAndAdjustQueryAACube(); +} + + void EntityItem::setDimensions(const glm::vec3& value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; } setScale(value); + checkAndAdjustQueryAACube(); } /// The maximum bounding cube for the entity, independent of it's rotation. @@ -1299,26 +1323,6 @@ AABox EntityItem::getAABox(bool& success) const { return _cachedAABox; } -AACube EntityItem::getQueryAACube(bool& success) const { - AACube queryAACube = SpatiallyNestable::getQueryAACube(success); - bool maxAACubeSuccess; - AACube maxAACube = getMaximumAACube(maxAACubeSuccess); - if (success) { - // allow server to patch up broken queryAACubes - if (maxAACubeSuccess && !queryAACube.contains(maxAACube)) { - getThisPointer()->setQueryAACube(maxAACube); - } - return _queryAACube; - } - // this is for when we've loaded an older json file that didn't have queryAACube properties. - success = maxAACubeSuccess; - if (maxAACubeSuccess) { - getThisPointer()->setQueryAACube(maxAACube); - } - return _queryAACube; -} - - // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 577bb406bc..7ce1d0c783 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -179,6 +179,10 @@ public: QString getDescription() const { return _description; } void setDescription(QString value) { _description = value; } + void checkAndAdjustQueryAACube(); + + virtual void setParentID(const QUuid& parentID); + /// Dimensions in meters (0.0 - TREE_SCALE) inline const glm::vec3 getDimensions() const { return getScale(); } virtual void setDimensions(const glm::vec3& value); @@ -238,9 +242,6 @@ public: AACube getMinimumAACube(bool& success) const; AABox getAABox(bool& success) const; /// axis aligned bounding box in world-frame (meters) - using SpatiallyNestable::getQueryAACube; - virtual AACube getQueryAACube(bool& success) const override; - const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } From df9ccf76ab98d56252a78d3df7b6edd583e3d360 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Mar 2016 13:48:27 -0800 Subject: [PATCH 180/258] fix animation-tests --- .../animation/src/AnimInverseKinematics.cpp | 7 + .../src/AnimInverseKinematicsTests.cpp | 123 +++++++++++------- tests/animation/src/AnimTests.cpp | 62 ++++----- 3 files changed, 114 insertions(+), 78 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 6a29ad61ac..4a6c3d819c 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -22,7 +22,13 @@ AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimN } AnimInverseKinematics::~AnimInverseKinematics() { + std::cout << "adebug dtor" << std::endl; // adebug clearConstraints(); + std::cout << "adebug dtor 002" << std::endl; // adebug + _accumulators.clear(); + std::cout << "adebug dtor 003 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug + _targetVarVec.clear(); + std::cout << "adebug dtor 004 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug } void AnimInverseKinematics::loadDefaultPoses(const AnimPoseVec& poses) { @@ -485,6 +491,7 @@ RotationConstraint* AnimInverseKinematics::getConstraint(int index) { } void AnimInverseKinematics::clearConstraints() { + std::cout << "adebug clearConstraints size = " << _constraints.size() << std::endl; // adebug std::map::iterator constraintItr = _constraints.begin(); while (constraintItr != _constraints.end()) { delete constraintItr->second; diff --git a/tests/animation/src/AnimInverseKinematicsTests.cpp b/tests/animation/src/AnimInverseKinematicsTests.cpp index bb15a1d257..2b10892f82 100644 --- a/tests/animation/src/AnimInverseKinematicsTests.cpp +++ b/tests/animation/src/AnimInverseKinematicsTests.cpp @@ -29,7 +29,7 @@ const glm::quat identity = glm::quat(); const glm::quat quaterTurnAroundZ = glm::angleAxis(0.5f * PI, zAxis); -void makeTestFBXJoints(std::vector& fbxJoints) { +void makeTestFBXJoints(FBXGeometry& geometry) { FBXJoint joint; joint.isFree = false; joint.freeLineage.clear(); @@ -61,29 +61,29 @@ void makeTestFBXJoints(std::vector& fbxJoints) { joint.name = "A"; joint.parentIndex = -1; joint.translation = origin; - fbxJoints.push_back(joint); + geometry.joints.push_back(joint); joint.name = "B"; joint.parentIndex = 0; joint.translation = xAxis; - fbxJoints.push_back(joint); + geometry.joints.push_back(joint); joint.name = "C"; joint.parentIndex = 1; joint.translation = xAxis; - fbxJoints.push_back(joint); + geometry.joints.push_back(joint); joint.name = "D"; joint.parentIndex = 2; joint.translation = xAxis; - fbxJoints.push_back(joint); + geometry.joints.push_back(joint); // compute each joint's transform - for (int i = 1; i < (int)fbxJoints.size(); ++i) { - FBXJoint& j = fbxJoints[i]; + for (int i = 1; i < (int)geometry.joints.size(); ++i) { + FBXJoint& j = geometry.joints[i]; int parentIndex = j.parentIndex; // World = ParentWorld * T * (Roff * Rp) * Rpre * R * Rpost * (Rp-1 * Soff * Sp * S * Sp-1) - j.transform = fbxJoints[parentIndex].transform * + j.transform = geometry.joints[parentIndex].transform * glm::translate(j.translation) * j.preTransform * glm::mat4_cast(j.preRotation * j.rotation * j.postRotation) * @@ -94,14 +94,14 @@ void makeTestFBXJoints(std::vector& fbxJoints) { } void AnimInverseKinematicsTests::testSingleChain() { - std::vector fbxJoints; - makeTestFBXJoints(fbxJoints); + FBXGeometry geometry; + makeTestFBXJoints(geometry); // create a skeleton and doll AnimPose offset; - AnimSkeleton* skeleton = new AnimSkeleton(fbxJoints, offset); - AnimSkeleton::Pointer skeletonPtr(skeleton); + AnimSkeleton::Pointer skeletonPtr = std::make_shared(geometry); AnimInverseKinematics ikDoll("doll"); + ikDoll.setSkeleton(skeletonPtr); { // easy test IK of joint C @@ -113,11 +113,11 @@ void AnimInverseKinematicsTests::testSingleChain() { pose.rot = identity; pose.trans = origin; - std::vector poses; + AnimPoseVec poses; poses.push_back(pose); pose.trans = xAxis; - for (int i = 1; i < (int)fbxJoints.size(); ++i) { + for (int i = 1; i < (int)geometry.joints.size(); ++i) { poses.push_back(pose); } ikDoll.loadPoses(poses); @@ -134,7 +134,8 @@ void AnimInverseKinematicsTests::testSingleChain() { AnimVariantMap varMap; varMap.set("positionD", targetPosition); varMap.set("rotationD", targetRotation); - ikDoll.setTargetVars("D", "positionD", "rotationD"); + varMap.set("targetType", (int)IKTarget::Type::RotationAndPosition); + ikDoll.setTargetVars(QString("D"), QString("positionD"), QString("rotationD"), QString("targetType")); AnimNode::Triggers triggers; // the IK solution should be: @@ -144,38 +145,49 @@ void AnimInverseKinematicsTests::testSingleChain() { // | // A------>B------>C // + + // iterate several times float dt = 1.0f; - ikDoll.evaluate(varMap, dt, triggers); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + const AnimPoseVec& relativePoses = ikDoll.overlay(varMap, dt, triggers, poses); // verify absolute results // NOTE: since we expect this solution to converge very quickly (one loop) // we can impose very tight error thresholds. - std::vector absolutePoses; + AnimPoseVec absolutePoses; + for (auto pose : poses) { + absolutePoses.push_back(pose); + } ikDoll.computeAbsolutePoses(absolutePoses); - float acceptableAngle = 0.0001f; - QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngle); - QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngle); - QCOMPARE_QUATS(absolutePoses[2].rot, quaterTurnAroundZ, acceptableAngle); - QCOMPARE_QUATS(absolutePoses[3].rot, quaterTurnAroundZ, acceptableAngle); + const float acceptableAngleError = 0.001f; + QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngleError); + QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngleError); + QCOMPARE_QUATS(absolutePoses[2].rot, quaterTurnAroundZ, acceptableAngleError); + QCOMPARE_QUATS(absolutePoses[3].rot, quaterTurnAroundZ, acceptableAngleError); - QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, EPSILON); - QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, targetPosition, EPSILON); + const float acceptableTranslationError = 0.025f; + QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, targetPosition, acceptableTranslationError); // verify relative results - const std::vector& relativePoses = ikDoll.getRelativePoses(); - QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngle); - QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngle); - QCOMPARE_QUATS(relativePoses[2].rot, quaterTurnAroundZ, acceptableAngle); - QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngle); + QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngleError); + QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngleError); + QCOMPARE_QUATS(relativePoses[2].rot, quaterTurnAroundZ, acceptableAngleError); + QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngleError); - QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, EPSILON); + QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, acceptableTranslationError); } - { // hard test IK of joint C // load intial poses that look like this: // @@ -188,8 +200,8 @@ void AnimInverseKinematicsTests::testSingleChain() { pose.scale = glm::vec3(1.0f); pose.rot = identity; pose.trans = origin; - - std::vector poses; + + AnimPoseVec poses; poses.push_back(pose); pose.trans = xAxis; @@ -211,15 +223,26 @@ void AnimInverseKinematicsTests::testSingleChain() { AnimVariantMap varMap; varMap.set("positionD", targetPosition); varMap.set("rotationD", targetRotation); - ikDoll.setTargetVars("D", "positionD", "rotationD"); + varMap.set("targetType", (int)IKTarget::Type::RotationAndPosition); + ikDoll.setTargetVars(QString("D"), QString("positionD"), QString("rotationD"), QString("targetType")); AnimNode::Triggers triggers; // the IK solution should be: // // A------>B------>C------>D // + + // iterate several times float dt = 1.0f; - ikDoll.evaluate(varMap, dt, triggers); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + const AnimPoseVec& relativePoses = ikDoll.overlay(varMap, dt, triggers, poses); // verify absolute results // NOTE: the IK algorithm doesn't converge very fast for full-reach targets, @@ -228,31 +251,33 @@ void AnimInverseKinematicsTests::testSingleChain() { // NOTE: constraints may help speed up convergence since some joints may get clamped // to maximum extension. TODO: experiment with tightening the error thresholds when // constraints are working. - std::vector absolutePoses; + AnimPoseVec absolutePoses; + for (auto pose : poses) { + absolutePoses.push_back(pose); + } ikDoll.computeAbsolutePoses(absolutePoses); - float acceptableAngle = 0.1f; // radians + float acceptableAngle = 0.01f; // radians QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngle); QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngle); QCOMPARE_QUATS(absolutePoses[2].rot, identity, acceptableAngle); QCOMPARE_QUATS(absolutePoses[3].rot, identity, acceptableAngle); - float acceptableDistance = 0.4f; - QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, EPSILON); + float acceptableDistance = 0.03f; + QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, acceptableDistance); QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, acceptableDistance); QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, acceptableDistance); QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, 3.0f * xAxis, acceptableDistance); // verify relative results - const std::vector& relativePoses = ikDoll.getRelativePoses(); QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngle); QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngle); QCOMPARE_QUATS(relativePoses[2].rot, identity, acceptableAngle); QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngle); - QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, EPSILON); + QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, acceptableDistance); + QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, acceptableDistance); + QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, acceptableDistance); + QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, acceptableDistance); } } diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 6812bb63b6..130b692fb0 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -38,8 +38,9 @@ void AnimTests::testClipInternalState() { float endFrame = 20.0f; float timeScale = 1.1f; bool loopFlag = true; + bool mirrorFlag = false; - AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag); + AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag); QVERIFY(clip.getID() == id); QVERIFY(clip.getType() == AnimNode::Type::Clip); @@ -49,6 +50,7 @@ void AnimTests::testClipInternalState() { QVERIFY(clip._endFrame == endFrame); QVERIFY(clip._timeScale == timeScale); QVERIFY(clip._loopFlag == loopFlag); + QVERIFY(clip._mirrorFlag == mirrorFlag); } static float framesToSec(float secs) { @@ -62,12 +64,13 @@ void AnimTests::testClipEvaulate() { float startFrame = 2.0f; float endFrame = 22.0f; float timeScale = 1.0f; - float loopFlag = true; + bool loopFlag = true; + bool mirrorFlag = false; auto vars = AnimVariantMap(); vars.set("FalseVar", false); - AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag); + AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag); AnimNode::Triggers triggers; clip.evaluate(vars, framesToSec(10.0f), triggers); @@ -97,7 +100,8 @@ void AnimTests::testClipEvaulateWithVars() { float startFrame = 2.0f; float endFrame = 22.0f; float timeScale = 1.0f; - float loopFlag = true; + bool loopFlag = true; + bool mirrorFlag = false; float startFrame2 = 22.0f; float endFrame2 = 100.0f; @@ -110,7 +114,7 @@ void AnimTests::testClipEvaulateWithVars() { vars.set("timeScale2", timeScale2); vars.set("loopFlag2", loopFlag2); - AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag); + AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag); clip.setStartFrameVar("startFrame2"); clip.setEndFrameVar("endFrame2"); clip.setTimeScaleVar("timeScale2"); @@ -583,23 +587,23 @@ void AnimTests::testExpressionEvaluator() { TEST_BOOL_EXPR(false && false); TEST_BOOL_EXPR(false && true); - TEST_BOOL_EXPR(true || false && true); - TEST_BOOL_EXPR(true || false && false); - TEST_BOOL_EXPR(true || true && true); - TEST_BOOL_EXPR(true || true && false); - TEST_BOOL_EXPR(false || false && true); - TEST_BOOL_EXPR(false || false && false); - TEST_BOOL_EXPR(false || true && true); - TEST_BOOL_EXPR(false || true && false); + TEST_BOOL_EXPR(true || (false && true)); + TEST_BOOL_EXPR(true || (false && false)); + TEST_BOOL_EXPR(true || (true && true)); + TEST_BOOL_EXPR(true || (true && false)); + TEST_BOOL_EXPR(false || (false && true)); + TEST_BOOL_EXPR(false || (false && false)); + TEST_BOOL_EXPR(false || (true && true)); + TEST_BOOL_EXPR(false || (true && false)); - TEST_BOOL_EXPR(true && false || true); - TEST_BOOL_EXPR(true && false || false); - TEST_BOOL_EXPR(true && true || true); - TEST_BOOL_EXPR(true && true || false); - TEST_BOOL_EXPR(false && false || true); - TEST_BOOL_EXPR(false && false || false); - TEST_BOOL_EXPR(false && true || true); - TEST_BOOL_EXPR(false && true || false); + TEST_BOOL_EXPR((true && false) || true); + TEST_BOOL_EXPR((true && false) || false); + TEST_BOOL_EXPR((true && true) || true); + TEST_BOOL_EXPR((true && true) || false); + TEST_BOOL_EXPR((false && false) || true); + TEST_BOOL_EXPR((false && false) || false); + TEST_BOOL_EXPR((false && true) || true); + TEST_BOOL_EXPR((false && true) || false); TEST_BOOL_EXPR(t || false); TEST_BOOL_EXPR(t || true); @@ -610,14 +614,14 @@ void AnimTests::testExpressionEvaluator() { TEST_BOOL_EXPR(!false); TEST_BOOL_EXPR(!true || true); - TEST_BOOL_EXPR(!true && !false || !true); - TEST_BOOL_EXPR(!true && !false || true); - TEST_BOOL_EXPR(!true && false || !true); - TEST_BOOL_EXPR(!true && false || true); - TEST_BOOL_EXPR(true && !false || !true); - TEST_BOOL_EXPR(true && !false || true); - TEST_BOOL_EXPR(true && false || !true); - TEST_BOOL_EXPR(true && false || true); + TEST_BOOL_EXPR((!true && !false) || !true); + TEST_BOOL_EXPR((!true && !false) || true); + TEST_BOOL_EXPR((!true && false) || !true); + TEST_BOOL_EXPR((!true && false) || true); + TEST_BOOL_EXPR((true && !false) || !true); + TEST_BOOL_EXPR((true && !false) || true); + TEST_BOOL_EXPR((true && false) || !true); + TEST_BOOL_EXPR((true && false) || true); TEST_BOOL_EXPR(!(true && f) || !t); TEST_BOOL_EXPR(!!!(t) && (!!f || true)); From 6ebb94b1f4605cbe11a1459782a3bb67eadd1aa7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Mar 2016 13:48:32 -0800 Subject: [PATCH 181/258] minor API cleanup of SwingLimitFunction API --- libraries/animation/src/SwingTwistConstraint.cpp | 11 ++--------- libraries/animation/src/SwingTwistConstraint.h | 3 --- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index 3bf661612e..3a2606c5ce 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -24,15 +24,8 @@ const int LAST_CLAMP_NO_BOUNDARY = 0; const int LAST_CLAMP_HIGH_BOUNDARY = 1; SwingTwistConstraint::SwingLimitFunction::SwingLimitFunction() { - setCone(PI); -} - -void SwingTwistConstraint::SwingLimitFunction::setCone(float maxAngle) { - _minDots.clear(); - float minDot = glm::clamp(maxAngle, MIN_MINDOT, MAX_MINDOT); - _minDots.push_back(minDot); - // push the first value to the back to establish cyclic boundary conditions - _minDots.push_back(minDot); + _minDots.push_back(-1.0f); + _minDots.push_back(-1.0f); } void SwingTwistConstraint::SwingLimitFunction::setMinDots(const std::vector& minDots) { diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index f73bbfb233..620e63e98b 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -59,9 +59,6 @@ public: public: SwingLimitFunction(); - /// \brief use a uniform conical swing limit - void setCone(float maxAngle); - /// \brief use a vector of lookup values for swing limits void setMinDots(const std::vector& minDots); From 749dcf2c1de2cd094bcb080a088f00ffb7421a2f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 10:19:50 -0800 Subject: [PATCH 182/258] dynamic adjustment for swing --- .../animation/src/SwingTwistConstraint.cpp | 167 +++++++++++- .../animation/src/SwingTwistConstraint.h | 26 +- .../animation/src/RotationConstraintTests.cpp | 253 +++++++++++++++++- tests/animation/src/RotationConstraintTests.h | 4 +- 4 files changed, 432 insertions(+), 18 deletions(-) diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index 3a2606c5ce..dd0a9ce0e8 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -26,23 +26,150 @@ const int LAST_CLAMP_HIGH_BOUNDARY = 1; SwingTwistConstraint::SwingLimitFunction::SwingLimitFunction() { _minDots.push_back(-1.0f); _minDots.push_back(-1.0f); + + _minDotIndexA = -1; + _minDotIndexB = -1; } +// In order to support the dynamic adjustment to swing limits we require +// that minDots have a minimum number of elements: +const int MIN_NUM_DOTS = 8; + void SwingTwistConstraint::SwingLimitFunction::setMinDots(const std::vector& minDots) { - uint32_t numDots = (uint32_t)minDots.size(); + int numDots = (int)minDots.size(); _minDots.clear(); if (numDots == 0) { - // push two copies of MIN_MINDOT - _minDots.push_back(MIN_MINDOT); + // push multiple copies of MIN_MINDOT + for (int i = 0; i < MIN_NUM_DOTS; ++i) { + _minDots.push_back(MIN_MINDOT); + } + // push one more for cyclic boundary conditions _minDots.push_back(MIN_MINDOT); } else { - _minDots.reserve(numDots); - for (uint32_t i = 0; i < numDots; ++i) { - _minDots.push_back(glm::clamp(minDots[i], MIN_MINDOT, MAX_MINDOT)); + // for minimal fidelity in the dynamic adjustment we expand the swing limit data until + // we have enough data points + int trueNumDots = numDots; + int numFiller = 0; + while(trueNumDots < MIN_NUM_DOTS) { + numFiller++; + trueNumDots += numDots; } - // push the first value to the back to establish cyclic boundary conditions + _minDots.reserve(trueNumDots); + + for (int i = 0; i < numDots; ++i) { + // push the next value + _minDots.push_back(glm::clamp(minDots[i], MIN_MINDOT, MAX_MINDOT)); + + if (numFiller > 0) { + // compute endpoints of line segment + float nearDot = glm::clamp(minDots[i], MIN_MINDOT, MAX_MINDOT); + int k = (i + 1) % numDots; + float farDot = glm::clamp(minDots[k], MIN_MINDOT, MAX_MINDOT); + + // fill the gap with interpolated values + for (int j = 0; j < numFiller; ++j) { + float delta = (float)(j + 1) / float(numFiller + 1); + _minDots.push_back((1.0f - delta) * nearDot + delta * farDot); + } + } + } + // push the first value to the back to for cyclic boundary conditions _minDots.push_back(_minDots[0]); } + _minDotIndexA = -1; + _minDotIndexB = -1; +} + +/// \param angle radian angle to update +/// \param minDotAdjustment minimum dot limit at that angle +void SwingTwistConstraint::SwingLimitFunction::dynamicallyAdjustMinDots(float theta, float minDotAdjustment) { + // What does "dynamic adjustment" mean? + // + // Consider a limitFunction that looks like this: + // + // 1+ + // | valid space + // | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // | + // | invalid space + // 0+------------------------------------------------ + // 0 pi/2 pi 3pi/2 2pi + // theta ---> + // + // If we wanted to modify the envelope to accept a single invalid point X + // then we would need to modify neighboring values A and B accordingly: + // + // 1+ adjustment for X at some thetaX + // | | + // | | + // +-----+. V .+-----+-----+-----+-----+ + // | - - + // | ' A--X--B ' + // 0+------------------------------------------------ + // 0 pi/2 pi 3pi/2 2pi + // + // The code below computes the values of A and B such that the line between them + // passes through the point X, and we get reasonable interpolation for nearby values + // of theta. The old AB values are saved for later restore. + + if (_minDotIndexA > -1) { + // retstore old values + _minDots[_minDotIndexA] = _minDotA; + _minDots[_minDotIndexB] = _minDotB; + + // handle cyclic boundary conditions + int lastIndex = (int)_minDots.size() - 1; + if (_minDotIndexA == 0) { + _minDots[lastIndex] = _minDotA; + } else if (_minDotIndexB == lastIndex) { + _minDots[0] = _minDotB; + } + } + + // extract the positive normalized fractional part of the theta + float integerPart; + float normalizedAngle = modff(theta / TWO_PI, &integerPart); + if (normalizedAngle < 0.0f) { + normalizedAngle += 1.0f; + } + + // interpolate between the two nearest points in the curve + float delta = modff(normalizedAngle * (float)(_minDots.size() - 1), &integerPart); + int indexA = (int)(integerPart); + int indexB = (indexA + 1) % _minDots.size(); + float interpolatedDot = _minDots[indexA] * (1.0f - delta) + _minDots[indexB] * delta; + + if (minDotAdjustment < interpolatedDot) { + // minDotAdjustment is outside the existing bounds so we must modify + + // remember the indices + _minDotIndexA = indexA; + _minDotIndexB = indexB; + + // save the old minDots + _minDotA = _minDots[_minDotIndexA]; + _minDotB = _minDots[_minDotIndexB]; + + // compute replacement values to _minDots that will provide a line segment + // that passes through minDotAdjustment while balancing the distortion between A and B. + // Note: the derivation of these formulae is left as an exercise to the reader. + float twiceUndershoot = 2.0f * (minDotAdjustment - interpolatedDot); + _minDots[_minDotIndexA] -= twiceUndershoot * (delta + 0.5f) * (delta - 1.0f); + _minDots[_minDotIndexB] -= twiceUndershoot * delta * (delta - 1.5f); + + // handle cyclic boundary conditions + int lastIndex = (int)_minDots.size() - 1; + if (_minDotIndexA == 0) { + _minDots[lastIndex] = _minDots[_minDotIndexA]; + } else if (_minDotIndexB == lastIndex) { + _minDots[0] = _minDots[_minDotIndexB]; + } + } else { + // minDotAdjustment is inside bounds so there is nothing to do + _minDotIndexA = -1; + _minDotIndexB = -1; + } } float SwingTwistConstraint::SwingLimitFunction::getMinDot(float theta) const { @@ -83,12 +210,12 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir }; std::vector limits; - uint32_t numLimits = (uint32_t)swungDirections.size(); + int numLimits = (int)swungDirections.size(); limits.reserve(numLimits); // compute the limit pairs: const glm::vec3 yAxis = glm::vec3(0.0f, 1.0f, 0.0f); - for (uint32_t i = 0; i < numLimits; ++i) { + for (int i = 0; i < numLimits; ++i) { float directionLength = glm::length(swungDirections[i]); if (directionLength > EPSILON) { glm::vec3 swingAxis = glm::cross(yAxis, swungDirections[i]); @@ -101,7 +228,7 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir } std::vector minDots; - numLimits = (uint32_t)limits.size(); + numLimits = (int)limits.size(); if (numLimits == 0) { // trivial case: nearly free constraint std::vector minDots; @@ -119,10 +246,10 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir // extrapolate evenly distributed limits for fast lookup table float deltaTheta = TWO_PI / (float)(numLimits); - uint32_t rightIndex = 0; - for (uint32_t i = 0; i < numLimits; ++i) { + int rightIndex = 0; + for (int i = 0; i < numLimits; ++i) { float theta = (float)i * deltaTheta; - uint32_t leftIndex = (rightIndex - 1) % numLimits; + int leftIndex = (rightIndex - 1) % numLimits; while (rightIndex < numLimits && theta > limits[rightIndex]._theta) { leftIndex = rightIndex++; } @@ -245,6 +372,20 @@ bool SwingTwistConstraint::apply(glm::quat& rotation) const { return false; } +void SwingTwistConstraint::dynamicallyAdjustLimits(const glm::quat& rotation) { + glm::quat postRotation = rotation * glm::inverse(_referenceRotation); + glm::quat swingRotation, twistRotation; + + const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); + swingTwistDecomposition(postRotation, yAxis, swingRotation, twistRotation); + + // we currently only handle swing limits + glm::vec3 swungY = swingRotation * yAxis; + glm::vec3 swingAxis = glm::cross(yAxis, swungY); + float theta = atan2f(-swingAxis.z, swingAxis.x); + _swingLimitFunction.dynamicallyAdjustMinDots(theta, swungY.y); +} + void SwingTwistConstraint::clearHistory() { _lastTwistBoundary = LAST_CLAMP_NO_BOUNDARY; } diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index 620e63e98b..df9da8cabe 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -53,8 +53,18 @@ public: void setLowerSpine(bool lowerSpine) { _lowerSpine = lowerSpine; } virtual bool isLowerSpine() const override { return _lowerSpine; } + /// \param rotation rotation to allow + /// \brief clear previous adjustment and adjust constraint limits to allow rotation + void dynamicallyAdjustLimits(const glm::quat& rotation); + + // for testing purposes + const std::vector& getMinDots() { return _swingLimitFunction.getMinDots(); } + // SwingLimitFunction is an implementation of the constraint check described in the paper: // "The Parameterization of Joint Rotation with the Unit Quaternion" by Quang Liu and Edmond C. Prakash + // + // The "dynamic adjustment" feature allows us to change the limits on the fly for one particular theta angle. + // class SwingLimitFunction { public: SwingLimitFunction(); @@ -62,12 +72,26 @@ public: /// \brief use a vector of lookup values for swing limits void setMinDots(const std::vector& minDots); + /// \param theta radian angle to new minDot + /// \param minDot minimum dot limit + /// \brief updates swing constraint to permit minDot at theta + void dynamicallyAdjustMinDots(float theta, float minDot); + /// \return minimum dotProduct between reference and swung axes float getMinDot(float theta) const; - protected: + // for testing purposes + const std::vector& getMinDots() { return _minDots; } + + private: // the limits are stored in a lookup table with cyclic boundary conditions std::vector _minDots; + + // these values used to restore dynamic adjustment + float _minDotA; + float _minDotB; + int8_t _minDotIndexA; + int8_t _minDotIndexB; }; /// \return reference to SwingLimitFunction instance for unit-testing diff --git a/tests/animation/src/RotationConstraintTests.cpp b/tests/animation/src/RotationConstraintTests.cpp index 7aacf26826..b0351721ae 100644 --- a/tests/animation/src/RotationConstraintTests.cpp +++ b/tests/animation/src/RotationConstraintTests.cpp @@ -56,7 +56,7 @@ void RotationConstraintTests::testElbowConstraint() { float startAngle = minAngle + smallAngle; float endAngle = maxAngle - smallAngle; float deltaAngle = (endAngle - startAngle) / (float)(numChecks - 1); - + for (float angle = startAngle; angle < endAngle + 0.5f * deltaAngle; angle += deltaAngle) { glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation; glm::quat outputRotation = inputRotation; @@ -115,9 +115,9 @@ void RotationConstraintTests::testSwingTwistConstraint() { shoulder.setTwistLimits(minTwistAngle, maxTwistAngle); float lowDot = 0.25f; float highDot = 0.75f; - // The swing constriants are more interesting: a vector of minimum dot products + // The swing constriants are more interesting: a vector of minimum dot products // as a function of theta around the twist axis. Our test function will be shaped - // like the square wave with amplitudes 0.25 and 0.75: + // like a square wave with amplitudes 0.25 and 0.75: // // | // 0.75 - o---o---o---o @@ -308,3 +308,250 @@ void RotationConstraintTests::testSwingTwistConstraint() { } } +void RotationConstraintTests::testDynamicSwingLimitFunction() { + SwingTwistConstraint::SwingLimitFunction limitFunction; + const float ACCEPTABLE_ERROR = 1.0e-6f; + + const float adjustmentDot = -0.5f; + + const float MIN_DOT = 0.5f; + { // initialize limitFunction + std::vector minDots; + minDots.push_back(MIN_DOT); + limitFunction.setMinDots(minDots); + } + + std::vector referenceDots; + { // verify limits and initialize referenceDots + const int MIN_NUM_DOTS = 8; + const std::vector& minDots = limitFunction.getMinDots(); + QVERIFY(minDots.size() >= MIN_NUM_DOTS); + + int numDots = (int)minDots.size(); + for (int i = 0; i < numDots; ++i) { + QCOMPARE_WITH_RELATIVE_ERROR(minDots[i], MIN_DOT, ACCEPTABLE_ERROR); + referenceDots.push_back(minDots[i]); + } + } + { // dynamically adjust limits + const std::vector& minDots = limitFunction.getMinDots(); + int numDots = (int)minDots.size(); + + float deltaTheta = TWO_PI / (float)(numDots - 1); + int indexA = 2; + int indexB = (indexA + 1) % numDots; + + { // dynamically adjust a data point + float theta = deltaTheta * (float)indexA; + float interpolatedDot = limitFunction.getMinDot(theta); + + // change indexA + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], adjustmentDot, ACCEPTABLE_ERROR); // indexA has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB has not changed + + // change indexB + theta = deltaTheta * (float)indexB; + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA has been restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], adjustmentDot, ACCEPTABLE_ERROR); // indexB has changed + + // restore + limitFunction.dynamicallyAdjustMinDots(theta, referenceDots[indexB] + 0.01f); // restore with a larger dot + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + } + { // dynamically adjust halfway between data points + float theta = deltaTheta * 0.5f * (float)(indexA + indexB); // halfway between two points + float interpolatedDot = limitFunction.getMinDot(theta); + float deltaDot = adjustmentDot - interpolatedDot; + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA] + deltaDot, ACCEPTABLE_ERROR); // indexA has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB] + deltaDot, ACCEPTABLE_ERROR); // indexB has changed + + limitFunction.dynamicallyAdjustMinDots(theta, interpolatedDot + 0.01f); // reset with something larger + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + } + { // dynamically adjust one-quarter between data points + float theta = deltaTheta * ((float)indexA + 0.25f); // one quarter past A towards B + float interpolatedDot = limitFunction.getMinDot(theta); + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QVERIFY(minDots[indexA] < adjustmentDot); // indexA should be less than minDot + QVERIFY(minDots[indexB] > adjustmentDot); // indexB should be larger than minDot + QVERIFY(minDots[indexB] < referenceDots[indexB]); // indexB should be less than what it was + + limitFunction.dynamicallyAdjustMinDots(theta, interpolatedDot + 0.01f); // reset with something larger + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + } + { // halfway between first two data points (boundary condition) + indexA = 0; + indexB = 1; + int indexZ = minDots.size() - 1; // far boundary condition + float theta = deltaTheta * 0.5f * (float)(indexA + indexB); // halfway between two points + float interpolatedDot = limitFunction.getMinDot(theta); + float deltaDot = adjustmentDot - interpolatedDot; + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA] + deltaDot, ACCEPTABLE_ERROR); // indexA has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB] + deltaDot, ACCEPTABLE_ERROR); // indexB has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexZ], referenceDots[indexZ] + deltaDot, ACCEPTABLE_ERROR); // indexZ has changed + + limitFunction.dynamicallyAdjustMinDots(theta, interpolatedDot + 0.01f); // reset with something larger + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexZ], referenceDots[indexZ], ACCEPTABLE_ERROR); // indexZ is restored + } + { // halfway between first two data points (boundary condition) + indexB = minDots.size() - 1; + indexA = indexB - 1; + int indexZ = 0; // far boundary condition + float theta = deltaTheta * 0.5f * (float)(indexA + indexB); // halfway between two points + float interpolatedDot = limitFunction.getMinDot(theta); + float deltaDot = adjustmentDot - interpolatedDot; + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA] + deltaDot, ACCEPTABLE_ERROR); // indexA has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB] + deltaDot, ACCEPTABLE_ERROR); // indexB has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexZ], referenceDots[indexZ] + deltaDot, ACCEPTABLE_ERROR); // indexZ has changed + + limitFunction.dynamicallyAdjustMinDots(theta, interpolatedDot + 0.01f); // reset with something larger + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexZ], referenceDots[indexZ], ACCEPTABLE_ERROR); // indexZ is restored + } + } +} + +void RotationConstraintTests::testDynamicSwingTwistConstraint() { + + const float ACCEPTABLE_ERROR = 1.0e-6f; + + // referenceRotation is the default rotation + float referenceAngle = 1.23f; + glm::vec3 referenceAxis = glm::normalize(glm::vec3(1.0f, 2.0f, -3.0f)); + glm::quat referenceRotation = glm::angleAxis(referenceAngle, referenceAxis); + + // the angle limits of the constriant about the hinge axis + float minTwistAngle = -PI / 2.0f; + float maxTwistAngle = PI / 2.0f; + + // build the constraint + SwingTwistConstraint shoulder; + shoulder.setReferenceRotation(referenceRotation); + shoulder.setTwistLimits(minTwistAngle, maxTwistAngle); + std::vector minDots; + const float MIN_DOT = 0.5f; + minDots.push_back(MIN_DOT); + shoulder.setSwingLimits(minDots); + + // verify resolution of the swing limits + const std::vector& shoulderMinDots = shoulder.getMinDots(); + const int MIN_NUM_DOTS = 8; + int numDots = shoulderMinDots.size(); + QVERIFY(numDots >= MIN_NUM_DOTS); + + // verify values of the swing limits + QCOMPARE_WITH_ABS_ERROR(shoulderMinDots[0], shoulderMinDots[numDots - 1], ACCEPTABLE_ERROR); // endpoints should be the same + for (int i = 0; i < numDots; ++i) { + QCOMPARE_WITH_ABS_ERROR(shoulderMinDots[i], MIN_DOT, ACCEPTABLE_ERROR); // all values should be the same + } + + float deltaTheta = TWO_PI / (float)(numDots - 1); + float theta = 1.5f * deltaTheta; + glm::vec3 swingAxis(cosf(theta), 0.0f, sinf(theta)); + float deltaSwing = 0.1f; + + { // compute rotation that should NOT be constrained + float swingAngle = acosf(MIN_DOT) - deltaSwing; + glm::quat swingRotation = glm::angleAxis(swingAngle, swingAxis); + glm::quat totalRotation = swingRotation * referenceRotation; + + // verify rotation is NOT constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(!shoulder.apply(constrainedRotation)); + } + + { // compute a rotation that should be barely constrained + float swingAngle = acosf(MIN_DOT) + deltaSwing; + glm::quat swingRotation = glm::angleAxis(swingAngle, swingAxis); + glm::quat totalRotation = swingRotation * referenceRotation; + + // verify rotation is constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); // should FAIL + } + + { // make a dynamic adjustment to the swing limits + const float SMALLER_MIN_DOT = -0.5f; + float swingAngle = acosf(SMALLER_MIN_DOT); + glm::quat swingRotation = glm::angleAxis(swingAngle, swingAxis); + glm::quat badRotation = swingRotation * referenceRotation; + + { // verify rotation is constrained + glm::quat constrainedRotation = badRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + + // now poke the SMALLER_MIN_DOT into the swing limits + shoulder.dynamicallyAdjustLimits(badRotation); + + // verify that if rotation is constrained then it is only by a little bit + constrainedRotation = badRotation; + bool constrained = shoulder.apply(constrainedRotation); + if (constrained) { + // Note: Q1 = dQ * Q0 --> dQ = Q1 * Q0^ + glm::quat dQ = constrainedRotation * glm::inverse(badRotation); + const float acceptableClampAngle = 0.01f; + float deltaAngle = glm::angle(dQ); + QVERIFY(deltaAngle < acceptableClampAngle); + } + } + + { // verify that other swing axes still use the old non-adjusted limits + float deltaTheta = TWO_PI / (float)(numDots - 1); + float otherTheta = 3.5f * deltaTheta; + glm::vec3 otherSwingAxis(cosf(otherTheta), 0.0f, sinf(otherTheta)); + + { // inside rotations should be unconstrained + float goodAngle = acosf(MIN_DOT) - deltaSwing; + glm::quat goodRotation = glm::angleAxis(goodAngle, otherSwingAxis) * referenceRotation; + QVERIFY(!shoulder.apply(goodRotation)); + } + { // outside rotations should be constrained + float badAngle = acosf(MIN_DOT) + deltaSwing; + glm::quat otherBadRotation = glm::angleAxis(badAngle, otherSwingAxis) * referenceRotation; + QVERIFY(shoulder.apply(otherBadRotation)); + + float constrainedAngle = glm::angle(otherBadRotation); + QCOMPARE_WITH_ABS_ERROR(constrainedAngle, acosf(MIN_DOT), 0.1f * deltaSwing); + } + } + + { // clear dynamic adjustment + float goodAngle = acosf(MIN_DOT) - deltaSwing; + glm::quat goodRotation = glm::angleAxis(goodAngle, swingAxis) * referenceRotation; + + // when we update with a goodRotation the dynamic adjustment is cleared + shoulder.dynamicallyAdjustLimits(goodRotation); + + // verify that the old badRotation, which was not constrained dynamically, is now constrained + glm::quat constrainedRotation = badRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + + // and the good rotation should not be constrained + constrainedRotation = goodRotation; + QVERIFY(!shoulder.apply(constrainedRotation)); + } + } +} + diff --git a/tests/animation/src/RotationConstraintTests.h b/tests/animation/src/RotationConstraintTests.h index 4fed3588e4..7c6d80d3eb 100644 --- a/tests/animation/src/RotationConstraintTests.h +++ b/tests/animation/src/RotationConstraintTests.h @@ -15,10 +15,12 @@ class RotationConstraintTests : public QObject { Q_OBJECT - + private slots: void testElbowConstraint(); void testSwingTwistConstraint(); + void testDynamicSwingLimitFunction(); + void testDynamicSwingTwistConstraint(); }; #endif // hifi_RotationConstraintTests_h From 4b7514479759fff0a09f027d927d3f6b070a06e5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 10:20:40 -0800 Subject: [PATCH 183/258] remove debug cruft --- libraries/animation/src/AnimInverseKinematics.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 4a6c3d819c..46e17c39d8 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -22,13 +22,9 @@ AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimN } AnimInverseKinematics::~AnimInverseKinematics() { - std::cout << "adebug dtor" << std::endl; // adebug clearConstraints(); - std::cout << "adebug dtor 002" << std::endl; // adebug _accumulators.clear(); - std::cout << "adebug dtor 003 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug _targetVarVec.clear(); - std::cout << "adebug dtor 004 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug } void AnimInverseKinematics::loadDefaultPoses(const AnimPoseVec& poses) { @@ -491,7 +487,6 @@ RotationConstraint* AnimInverseKinematics::getConstraint(int index) { } void AnimInverseKinematics::clearConstraints() { - std::cout << "adebug clearConstraints size = " << _constraints.size() << std::endl; // adebug std::map::iterator constraintItr = _constraints.begin(); while (constraintItr != _constraints.end()) { delete constraintItr->second; From c9f988d34048de746cae6db4fc15611709ad5d72 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 11:06:58 -0800 Subject: [PATCH 184/258] dynamic adjustment for twist --- .../animation/src/SwingTwistConstraint.cpp | 120 +++++++++++------- .../animation/src/SwingTwistConstraint.h | 7 + 2 files changed, 83 insertions(+), 44 deletions(-) diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index dd0a9ce0e8..72659ff09d 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -13,6 +13,7 @@ #include #include +#include #include @@ -31,7 +32,7 @@ SwingTwistConstraint::SwingLimitFunction::SwingLimitFunction() { _minDotIndexB = -1; } -// In order to support the dynamic adjustment to swing limits we require +// In order to support the dynamic adjustment to swing limits we require // that minDots have a minimum number of elements: const int MIN_NUM_DOTS = 8; @@ -214,11 +215,10 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir limits.reserve(numLimits); // compute the limit pairs: - const glm::vec3 yAxis = glm::vec3(0.0f, 1.0f, 0.0f); for (int i = 0; i < numLimits; ++i) { float directionLength = glm::length(swungDirections[i]); if (directionLength > EPSILON) { - glm::vec3 swingAxis = glm::cross(yAxis, swungDirections[i]); + glm::vec3 swingAxis = glm::cross(Vectors::UNIT_Y, swungDirections[i]); float theta = atan2f(-swingAxis.z, swingAxis.x); if (theta < 0.0f) { theta += TWO_PI; @@ -285,51 +285,57 @@ void SwingTwistConstraint::setTwistLimits(float minTwist, float maxTwist) { _maxTwist = glm::max(minTwist, maxTwist); _lastTwistBoundary = LAST_CLAMP_NO_BOUNDARY; + _twistAdjusted = false; +} + +// private +float SwingTwistConstraint::handleTwistBoundaryConditions(float twistAngle) const { + // adjust measured twistAngle according to clamping history + switch (_lastTwistBoundary) { + case LAST_CLAMP_LOW_BOUNDARY: + // clamp to min + if (twistAngle > _maxTwist) { + twistAngle -= TWO_PI; + } + break; + case LAST_CLAMP_HIGH_BOUNDARY: + // clamp to max + if (twistAngle < _minTwist) { + twistAngle += TWO_PI; + } + break; + default: // LAST_CLAMP_NO_BOUNDARY + // clamp to nearest boundary + float midBoundary = 0.5f * (_maxTwist + _minTwist + TWO_PI); + if (twistAngle > midBoundary) { + // lower boundary is closer --> phase down one cycle + twistAngle -= TWO_PI; + } else if (twistAngle < midBoundary - TWO_PI) { + // higher boundary is closer --> phase up one cycle + twistAngle += TWO_PI; + } + break; + } + return twistAngle; } bool SwingTwistConstraint::apply(glm::quat& rotation) const { // decompose the rotation into first twist about yAxis, then swing about something perp - const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); // NOTE: rotation = postRotation * referenceRotation glm::quat postRotation = rotation * glm::inverse(_referenceRotation); glm::quat swingRotation, twistRotation; - swingTwistDecomposition(postRotation, yAxis, swingRotation, twistRotation); + swingTwistDecomposition(postRotation, Vectors::UNIT_Y, swingRotation, twistRotation); // NOTE: postRotation = swingRotation * twistRotation - // compute twistAngle + // compute raw twistAngle float twistAngle = 2.0f * acosf(fabsf(twistRotation.w)); - const glm::vec3 xAxis = glm::vec3(1.0f, 0.0f, 0.0f); - glm::vec3 twistedX = twistRotation * xAxis; - twistAngle *= copysignf(1.0f, glm::dot(glm::cross(xAxis, twistedX), yAxis)); + glm::vec3 twistedX = twistRotation * Vectors::UNIT_X; + twistAngle *= copysignf(1.0f, glm::dot(glm::cross(Vectors::UNIT_X, twistedX), Vectors::UNIT_Y)); bool somethingClamped = false; if (_minTwist != _maxTwist) { - // adjust measured twistAngle according to clamping history - switch (_lastTwistBoundary) { - case LAST_CLAMP_LOW_BOUNDARY: - // clamp to min - if (twistAngle > _maxTwist) { - twistAngle -= TWO_PI; - } - break; - case LAST_CLAMP_HIGH_BOUNDARY: - // clamp to max - if (twistAngle < _minTwist) { - twistAngle += TWO_PI; - } - break; - default: // LAST_CLAMP_NO_BOUNDARY - // clamp to nearest boundary - float midBoundary = 0.5f * (_maxTwist + _minTwist + TWO_PI); - if (twistAngle > midBoundary) { - // lower boundary is closer --> phase down one cycle - twistAngle -= TWO_PI; - } else if (twistAngle < midBoundary - TWO_PI) { - // higher boundary is closer --> phase up one cycle - twistAngle += TWO_PI; - } - break; - } + // twist limits apply --> figure out which limit we're hitting, if any + twistAngle = handleTwistBoundaryConditions(twistAngle); // clamp twistAngle float clampedTwistAngle = glm::clamp(twistAngle, _minTwist, _maxTwist); @@ -346,15 +352,15 @@ bool SwingTwistConstraint::apply(glm::quat& rotation) const { // clamp the swing // The swingAxis is always perpendicular to the reference axis (yAxis in the constraint's frame). - glm::vec3 swungY = swingRotation * yAxis; - glm::vec3 swingAxis = glm::cross(yAxis, swungY); + glm::vec3 swungY = swingRotation * Vectors::UNIT_Y; + glm::vec3 swingAxis = glm::cross(Vectors::UNIT_Y, swungY); float axisLength = glm::length(swingAxis); if (axisLength > EPSILON) { // The limit of swing is a function of "theta" which can be computed from the swingAxis // (which is in the constraint's ZX plane). float theta = atan2f(-swingAxis.z, swingAxis.x); float minDot = _swingLimitFunction.getMinDot(theta); - if (glm::dot(swungY, yAxis) < minDot) { + if (glm::dot(swungY, Vectors::UNIT_Y) < minDot) { // The swing limits are violated so we extract the angle from midDot and // use it to supply a new rotation. swingAxis /= axisLength; @@ -365,7 +371,7 @@ bool SwingTwistConstraint::apply(glm::quat& rotation) const { if (somethingClamped) { // update the rotation - twistRotation = glm::angleAxis(twistAngle, yAxis); + twistRotation = glm::angleAxis(twistAngle, Vectors::UNIT_Y); rotation = swingRotation * twistRotation * _referenceRotation; return true; } @@ -376,14 +382,40 @@ void SwingTwistConstraint::dynamicallyAdjustLimits(const glm::quat& rotation) { glm::quat postRotation = rotation * glm::inverse(_referenceRotation); glm::quat swingRotation, twistRotation; - const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); - swingTwistDecomposition(postRotation, yAxis, swingRotation, twistRotation); + swingTwistDecomposition(postRotation, Vectors::UNIT_Y, swingRotation, twistRotation); - // we currently only handle swing limits - glm::vec3 swungY = swingRotation * yAxis; - glm::vec3 swingAxis = glm::cross(yAxis, swungY); + // adjust swing limits + glm::vec3 swungY = swingRotation * Vectors::UNIT_Y; + glm::vec3 swingAxis = glm::cross(Vectors::UNIT_Y, swungY); float theta = atan2f(-swingAxis.z, swingAxis.x); _swingLimitFunction.dynamicallyAdjustMinDots(theta, swungY.y); + + // restore twist limits + if (_twistAdjusted) { + _minTwist = _oldMinTwist; + _maxTwist = _oldMaxTwist; + _twistAdjusted = false; + } + + if (_minTwist != _maxTwist) { + // compute twistAngle + float twistAngle = 2.0f * acosf(fabsf(twistRotation.w)); + glm::vec3 twistedX = twistRotation * Vectors::UNIT_X; + twistAngle *= copysignf(1.0f, glm::dot(glm::cross(Vectors::UNIT_X, twistedX), Vectors::UNIT_Y)); + twistAngle = handleTwistBoundaryConditions(twistAngle); + + if (twistAngle < _minTwist || twistAngle > _maxTwist) { + // expand twist limits + _twistAdjusted = true; + _oldMinTwist = _minTwist; + _oldMaxTwist = _maxTwist; + if (twistAngle < _minTwist) { + _minTwist = twistAngle; + } else if (twistAngle > _maxTwist) { + _maxTwist = twistAngle; + } + } + } } void SwingTwistConstraint::clearHistory() { diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index df9da8cabe..4734aa8b9d 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -100,15 +100,22 @@ public: /// \brief exposed for unit testing void clearHistory(); +private: + float handleTwistBoundaryConditions(float twistAngle) const; + protected: SwingLimitFunction _swingLimitFunction; float _minTwist; float _maxTwist; + float _oldMinTwist; + float _oldMaxTwist; + // We want to remember the LAST clamped boundary, so we an use it even when the far boundary is closer. // This reduces "pops" when the input twist angle goes far beyond and wraps around toward the far boundary. mutable int _lastTwistBoundary; bool _lowerSpine { false }; + bool _twistAdjusted { false }; }; #endif // hifi_SwingTwistConstraint_h From 71a81331d19a80e37c3dfb774ba5a9b7db858ff2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 13:20:03 -0800 Subject: [PATCH 185/258] unit tests for dynamic twist limit adjustment --- .../animation/src/RotationConstraintTests.cpp | 101 +++++++++++++++++- tests/animation/src/RotationConstraintTests.h | 3 +- 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/tests/animation/src/RotationConstraintTests.cpp b/tests/animation/src/RotationConstraintTests.cpp index b0351721ae..f828201a81 100644 --- a/tests/animation/src/RotationConstraintTests.cpp +++ b/tests/animation/src/RotationConstraintTests.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -433,8 +434,7 @@ void RotationConstraintTests::testDynamicSwingLimitFunction() { } } -void RotationConstraintTests::testDynamicSwingTwistConstraint() { - +void RotationConstraintTests::testDynamicSwing() { const float ACCEPTABLE_ERROR = 1.0e-6f; // referenceRotation is the default rotation @@ -489,7 +489,7 @@ void RotationConstraintTests::testDynamicSwingTwistConstraint() { // verify rotation is constrained glm::quat constrainedRotation = totalRotation; - QVERIFY(shoulder.apply(constrainedRotation)); // should FAIL + QVERIFY(shoulder.apply(constrainedRotation)); } { // make a dynamic adjustment to the swing limits @@ -555,3 +555,98 @@ void RotationConstraintTests::testDynamicSwingTwistConstraint() { } } +void RotationConstraintTests::testDynamicTwist() { + // referenceRotation is the default rotation + float referenceAngle = 1.23f; + glm::vec3 referenceAxis = glm::normalize(glm::vec3(1.0f, 2.0f, -3.0f)); + glm::quat referenceRotation = glm::angleAxis(referenceAngle, referenceAxis); + + // the angle limits of the constriant about the hinge axis + const float minTwistAngle = -PI / 2.0f; + const float maxTwistAngle = PI / 2.0f; + + // build the constraint + SwingTwistConstraint shoulder; + shoulder.setReferenceRotation(referenceRotation); + shoulder.setTwistLimits(minTwistAngle, maxTwistAngle); + + glm::vec3 twistAxis = Vectors::UNIT_Y; + float deltaTwist = 0.1f; + + { // compute min rotation that should NOT be constrained + float twistAngle = minTwistAngle + deltaTwist; + glm::quat twistRotation = glm::angleAxis(twistAngle, twistAxis); + glm::quat totalRotation = twistRotation * referenceRotation; + + // verify rotation is NOT constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(!shoulder.apply(constrainedRotation)); + } + { // compute max rotation that should NOT be constrained + float twistAngle = maxTwistAngle - deltaTwist; + glm::quat twistRotation = glm::angleAxis(twistAngle, twistAxis); + glm::quat totalRotation = twistRotation * referenceRotation; + + // verify rotation is NOT constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(!shoulder.apply(constrainedRotation)); + } + { // compute a min rotation that should be barely constrained + float twistAngle = minTwistAngle - deltaTwist; + glm::quat twistRotation = glm::angleAxis(twistAngle, twistAxis); + glm::quat totalRotation = twistRotation * referenceRotation; + + // verify rotation is constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + + // adjust the constraint and verify rotation is NOT constrained + shoulder.dynamicallyAdjustLimits(totalRotation); + constrainedRotation = totalRotation; + bool constrained = shoulder.apply(constrainedRotation); + if (constrained) { + // or, if it is constrained then the adjustment is very small + // Note: Q1 = dQ * Q0 --> dQ = Q1 * Q0^ + glm::quat dQ = constrainedRotation * glm::inverse(totalRotation); + const float acceptableClampAngle = 0.01f; + float deltaAngle = glm::angle(dQ); + QVERIFY(deltaAngle < acceptableClampAngle); + } + + // clear the adjustment using a null rotation + shoulder.dynamicallyAdjustLimits(glm::quat()); + + // verify that rotation is constrained again + constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + } + { // compute a min rotation that should be barely constrained + float twistAngle = maxTwistAngle + deltaTwist; + glm::quat twistRotation = glm::angleAxis(twistAngle, twistAxis); + glm::quat totalRotation = twistRotation * referenceRotation; + + // verify rotation is constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + + // adjust the constraint and verify rotation is NOT constrained + shoulder.dynamicallyAdjustLimits(totalRotation); + constrainedRotation = totalRotation; + bool constrained = shoulder.apply(constrainedRotation); + if (constrained) { + // or, if it is constrained then the adjustment is very small + // Note: Q1 = dQ * Q0 --> dQ = Q1 * Q0^ + glm::quat dQ = constrainedRotation * glm::inverse(totalRotation); + const float acceptableClampAngle = 0.01f; + float deltaAngle = glm::angle(dQ); + QVERIFY(deltaAngle < acceptableClampAngle); + } + + // clear the adjustment using a null rotation + shoulder.dynamicallyAdjustLimits(glm::quat()); + + // verify that rotation is constrained again + constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + } +} diff --git a/tests/animation/src/RotationConstraintTests.h b/tests/animation/src/RotationConstraintTests.h index 7c6d80d3eb..e63d08bc1f 100644 --- a/tests/animation/src/RotationConstraintTests.h +++ b/tests/animation/src/RotationConstraintTests.h @@ -20,7 +20,8 @@ private slots: void testElbowConstraint(); void testSwingTwistConstraint(); void testDynamicSwingLimitFunction(); - void testDynamicSwingTwistConstraint(); + void testDynamicSwing(); + void testDynamicTwist(); }; #endif // hifi_RotationConstraintTests_h From 48efbba335c93dd6f31f0984ad2b34148d3b3791 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 14:44:43 -0800 Subject: [PATCH 186/258] use dynamic constraints for IK --- libraries/animation/src/AnimInverseKinematics.cpp | 11 +++++++++++ libraries/animation/src/RotationConstraint.h | 4 ++++ libraries/animation/src/SwingTwistConstraint.h | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 46e17c39d8..f4df7ada82 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -396,6 +396,17 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars } _relativePoses[i].trans = underPoses[i].trans; } + + if (!_relativePoses.empty()) { + // Sometimes the underpose itself can violate the constraints. Rather than + // clamp the animation we dynamically expand each constraint to accomodate it. + std::map::iterator constraintItr = _constraints.begin(); + while (constraintItr != _constraints.end()) { + int index = constraintItr->first; + constraintItr->second->dynamicallyAdjustLimits(_relativePoses[index].rot); + ++constraintItr; + } + } } if (!_relativePoses.empty()) { diff --git a/libraries/animation/src/RotationConstraint.h b/libraries/animation/src/RotationConstraint.h index 0745500582..9e34537cab 100644 --- a/libraries/animation/src/RotationConstraint.h +++ b/libraries/animation/src/RotationConstraint.h @@ -31,6 +31,10 @@ public: /// \return true if this constraint is part of lower spine virtual bool isLowerSpine() const { return false; } + /// \param rotation rotation to allow + /// \brief clear previous adjustment and adjust constraint limits to allow rotation + virtual void dynamicallyAdjustLimits(const glm::quat& rotation) {} + protected: glm::quat _referenceRotation = glm::quat(); }; diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index 4734aa8b9d..93d7449d8f 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -55,7 +55,7 @@ public: /// \param rotation rotation to allow /// \brief clear previous adjustment and adjust constraint limits to allow rotation - void dynamicallyAdjustLimits(const glm::quat& rotation); + virtual void dynamicallyAdjustLimits(const glm::quat& rotation) override; // for testing purposes const std::vector& getMinDots() { return _swingLimitFunction.getMinDots(); } From 1e8706b1da6eaee6396a6174c36bcb70ffd1dff9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 14:47:53 -0800 Subject: [PATCH 187/258] remove debug print --- libraries/entities/src/EntityItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 71be12682b..c4d1280ef3 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1210,7 +1210,6 @@ void EntityItem::checkAndAdjustQueryAACube() { // allow server to patch up broken queryAACubes EntityTreePointer tree = getTree(); if (tree) { - qDebug() << "EntityItem::checkAndAdjustQueryAACube" << getName(); EntityItemProperties properties; properties.setQueryAACube(maxAACube); tree->updateEntity(getID(), properties); From 9dcdf26567f5829b9973ede55b5c27b47988eb05 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 11 Mar 2016 15:15:30 -0800 Subject: [PATCH 188/258] Only consider model transparent if all texs are --- .../model-networking/src/model-networking/ModelCache.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index af9fe97e93..3f7e0405d4 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -135,7 +135,7 @@ bool NetworkGeometry::isLoadedWithTextures() const { } if (!_isLoadedWithTextures) { - _hasTransparentTextures = false; + _hasTransparentTextures = true; for (auto&& material : _materials) { if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || @@ -152,7 +152,8 @@ bool NetworkGeometry::isLoadedWithTextures() const { const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); material->_material->setTransparentTexture(isTransparentTexture); - _hasTransparentTextures = _hasTransparentTextures || isTransparentTexture; + // FIXME: Materials with *some* transparent textures seem to give all *other* textures alphas of 0. + _hasTransparentTextures = isTransparentTexture && _hasTransparentTextures; } } From 895920a211f4e9a91bed0e54dc2492ca40628ffe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 15:19:41 -0800 Subject: [PATCH 189/258] short circuit upload when file cannot be opened --- libraries/networking/src/AssetUpload.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index f99f5badb6..077a0388cf 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -69,6 +69,8 @@ void AssetUpload::start() { // emit that we are done emit finished(this, QString()); + + return; } } From 6d6a53a69a30986e7fb19d24720fc67016ff4b10 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 13:27:45 -0800 Subject: [PATCH 190/258] use timer for upload click handle to avoid focus issue --- interface/resources/qml/AssetServer.qml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 1be5867413..48c005270f 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -447,7 +447,22 @@ Window { width: 155 enabled: fileUrlTextField.text != "" - onClicked: root.uploadClicked() + onClicked: uploadClickedTimer.running = true + + // For some reason trigginer an API that enters + // an internal event loop directly from the button clicked + // trigger below causes the appliction to behave oddly. + // Most likely because the button onClicked handling is never + // completed until the function returns. + // FIXME find a better way of handling the input dialogs that + // doesn't trigger this. + Timer { + id: uploadClickedTimer + interval: 5 + repeat: false + running: false + onTriggered: uploadClicked(); + } } } From 31f0e4a919ba66fe17aab67cfaae8b64cc6d0c0f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 13:32:50 -0800 Subject: [PATCH 191/258] disable the rename and delete buttons if nothing selected --- interface/resources/qml/AssetServer.qml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 48c005270f..a1c2fc2398 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -272,6 +272,10 @@ Window { }); } + function itemSelected() { + return treeView.selection.hasSelection() + } + Column { width: pane.contentWidth @@ -317,6 +321,7 @@ Window { width: 80 onClicked: root.renameFile() + enabled: treeView.selection.hasSelection } HifiControls.Button { @@ -329,6 +334,7 @@ Window { width: 80 onClicked: root.deleteFile() + enabled: treeView.selection.hasSelection } } From 188712a55bec61e2d0c2975c9026a88a9854c281 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 14:13:42 -0800 Subject: [PATCH 192/258] select a right-clicked item in asset browser --- interface/resources/qml/AssetServer.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index a1c2fc2398..82970011a0 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -379,6 +379,9 @@ Window { acceptedButtons: Qt.RightButton onClicked: { var index = treeView.indexAt(mouse.x, mouse.y); + + treeView.selection.setCurrentIndex(index, 0x0002); + contextMenu.currentIndex = index; contextMenu.popup(); } From 890266e0bdde2d1edf77bfb8691b9c9cf0f299de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 15:45:44 -0800 Subject: [PATCH 193/258] shrink message dialog to contentWidth --- interface/resources/qml/dialogs/MessageDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index 4a25c51012..4275428d31 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -72,7 +72,7 @@ ModalWindow { readonly property int maxHeight: 720 function resize() { - var targetWidth = mainTextContainer.width + var targetWidth = mainTextContainer.contentWidth var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y + (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0) + buttons.height From 5f05d576cc5e5abff9d4632c40345c8fb653d1be Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 15:55:42 -0800 Subject: [PATCH 194/258] move checkAndAdjustQueryAACube into SpatiallyNestable --- libraries/entities/src/EntityItem.cpp | 46 ++++++++++++++-------- libraries/entities/src/EntityItem.h | 4 +- libraries/entities/src/EntityTree.cpp | 22 +++++++---- libraries/shared/src/SpatiallyNestable.cpp | 11 +++++- libraries/shared/src/SpatiallyNestable.h | 3 +- 5 files changed, 57 insertions(+), 29 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c4d1280ef3..efd6b26600 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1202,25 +1202,24 @@ const Transform EntityItem::getTransformToCenter(bool& success) const { return result; } -void EntityItem::checkAndAdjustQueryAACube() { - bool maxAACubeSuccess; - AACube maxAACube = getMaximumAACube(maxAACubeSuccess); - if (maxAACubeSuccess) { - if (!_queryAACubeSet || !_queryAACube.contains(maxAACube)) { - // allow server to patch up broken queryAACubes - EntityTreePointer tree = getTree(); - if (tree) { - EntityItemProperties properties; - properties.setQueryAACube(maxAACube); - tree->updateEntity(getID(), properties); - } - } - } -} +// void EntityItem::checkAndAdjustQueryAACube() { +// bool maxAACubeSuccess; +// AACube maxAACube = getMaximumAACube(maxAACubeSuccess); +// if (maxAACubeSuccess) { +// if (!_queryAACubeSet || !_queryAACube.contains(maxAACube)) { +// // allow server to patch up broken queryAACubes +// EntityTreePointer tree = getTree(); +// if (tree) { +// EntityItemProperties properties; +// properties.setQueryAACube(maxAACube); +// tree->updateEntity(getID(), properties); +// } +// } +// } +// } void EntityItem::setParentID(const QUuid& parentID) { SpatiallyNestable::setParentID(parentID); - checkAndAdjustQueryAACube(); } @@ -1229,7 +1228,6 @@ void EntityItem::setDimensions(const glm::vec3& value) { return; } setScale(value); - checkAndAdjustQueryAACube(); } /// The maximum bounding cube for the entity, independent of it's rotation. @@ -1322,6 +1320,20 @@ AABox EntityItem::getAABox(bool& success) const { return _cachedAABox; } +AACube EntityItem::getQueryAACube(bool& success) const { + AACube result = SpatiallyNestable::getQueryAACube(success); + if (success) { + return result; + } + // this is for when we've loaded an older json file that didn't have queryAACube properties. + result = getMaximumAACube(success); + if (success) { + _queryAACube = result; + _queryAACubeSet = true; + } + return result; +} + // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7ce1d0c783..41dd423f92 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -179,8 +179,6 @@ public: QString getDescription() const { return _description; } void setDescription(QString value) { _description = value; } - void checkAndAdjustQueryAACube(); - virtual void setParentID(const QUuid& parentID); /// Dimensions in meters (0.0 - TREE_SCALE) @@ -242,6 +240,8 @@ public: AACube getMinimumAACube(bool& success) const; AABox getAABox(bool& success) const; /// axis aligned bounding box in world-frame (meters) + using SpatiallyNestable::getQueryAACube; + virtual AACube getQueryAACube(bool& success) const override; const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 4c3412edd3..2a37d19dd9 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -992,15 +992,21 @@ void EntityTree::fixupMissingParents() { EntityItemWeakPointer entityWP = iter.next(); EntityItemPointer entity = entityWP.lock(); if (entity) { - bool success; - AACube newCube = entity->getQueryAACube(success); - if (success) { - // this entity's parent (or ancestry) was previously not fully known, and now is. Update its - // location in the EntityTree. - moveOperator.addEntityToMoveList(entity, newCube); - iter.remove(); - entity->markAncestorMissing(false); + bool maxAACubeSuccess; + AACube maxAACube = entity->getMaximumAACube(maxAACubeSuccess); + bool queryAACubeSuccess; + AACube newCube = entity->getQueryAACube(queryAACubeSuccess); + if (!maxAACubeSuccess || !queryAACubeSuccess) { + continue; } + if (!newCube.contains(maxAACube)) { + newCube = maxAACube; + } + // this entity's parent (or ancestry) was previously not fully known, and now is. Update its + // location in the EntityTree. + moveOperator.addEntityToMoveList(entity, newCube); + iter.remove(); + entity->markAncestorMissing(false); } else { // entity was deleted before we found its parent. iter.remove(); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index c8dceaa905..cc4ff2cf1c 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -752,6 +752,7 @@ void SpatiallyNestable::forEachDescendant(std::functionlocationChanged(); }); @@ -761,13 +762,21 @@ AACube SpatiallyNestable::getMaximumAACube(bool& success) const { return AACube(getPosition(success) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize); } +void SpatiallyNestable::checkAndAdjustQueryAACube() { + bool success; + AACube maxAACube = getMaximumAACube(success); + if (success && (!_queryAACubeSet || !_queryAACube.contains(maxAACube))) { + setQueryAACube(maxAACube); + } +} + void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) { if (queryAACube.containsNaN()) { qDebug() << "SpatiallyNestable::setQueryAACube -- cube contains NaN"; return; } _queryAACube = queryAACube; - if (queryAACube.getScale() > 0.0f) { + if (_queryAACube.getScale() > 0.0f) { _queryAACubeSet = true; } } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index ee6cccc7a8..e6728bc923 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -81,6 +81,7 @@ public: virtual glm::vec3 getParentAngularVelocity(bool& success) const; virtual AACube getMaximumAACube(bool& success) const; + virtual void checkAndAdjustQueryAACube(); virtual bool computePuffedQueryAACube(); virtual void setQueryAACube(const AACube& queryAACube); @@ -156,7 +157,7 @@ protected: mutable QHash _children; virtual void locationChanged(); // called when a this object's location has changed - virtual void dimensionsChanged() {} // called when a this object's dimensions have changed + virtual void dimensionsChanged() { checkAndAdjustQueryAACube(); } // called when a this object's dimensions have changed // _queryAACube is used to decide where something lives in the octree mutable AACube _queryAACube; From 01659cf93b49cf511db242841ff4500fd9744bbf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 16:21:20 -0800 Subject: [PATCH 195/258] try, try again --- .../src/RenderableModelEntityItem.cpp | 19 ---------------- libraries/entities/src/EntityItem.cpp | 22 +------------------ libraries/entities/src/EntityItem.h | 3 +-- libraries/shared/src/SpatiallyNestable.cpp | 4 +++- 4 files changed, 5 insertions(+), 43 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2734d968a9..c637cf4bb9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -74,26 +74,7 @@ void RenderableModelEntityItem::loader() { void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { _dimensionsInitialized = true; - - bool success; - AACube queryAACube = getQueryAACube(success); - ModelEntityItem::setDimensions(value); - - AACube maxAACube = getMaximumAACube(success); - if (!success) { - return; - } - - if (!success || !queryAACube.contains(maxAACube)) { - EntityItemProperties properties; - properties.setQueryAACube(maxAACube); - qCDebug(entitiesrenderer) << "Auto-setting queryAACube:" << (!getName().isEmpty() ? getName() : getModelURL()); - QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", - Qt::QueuedConnection, - Q_ARG(QUuid, getEntityItemID()), - Q_ARG(EntityItemProperties, properties)); - } } bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index efd6b26600..3c918a0a77 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1202,27 +1202,6 @@ const Transform EntityItem::getTransformToCenter(bool& success) const { return result; } -// void EntityItem::checkAndAdjustQueryAACube() { -// bool maxAACubeSuccess; -// AACube maxAACube = getMaximumAACube(maxAACubeSuccess); -// if (maxAACubeSuccess) { -// if (!_queryAACubeSet || !_queryAACube.contains(maxAACube)) { -// // allow server to patch up broken queryAACubes -// EntityTreePointer tree = getTree(); -// if (tree) { -// EntityItemProperties properties; -// properties.setQueryAACube(maxAACube); -// tree->updateEntity(getID(), properties); -// } -// } -// } -// } - -void EntityItem::setParentID(const QUuid& parentID) { - SpatiallyNestable::setParentID(parentID); -} - - void EntityItem::setDimensions(const glm::vec3& value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; @@ -1334,6 +1313,7 @@ AACube EntityItem::getQueryAACube(bool& success) const { return result; } + // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 41dd423f92..577bb406bc 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -179,8 +179,6 @@ public: QString getDescription() const { return _description; } void setDescription(QString value) { _description = value; } - virtual void setParentID(const QUuid& parentID); - /// Dimensions in meters (0.0 - TREE_SCALE) inline const glm::vec3 getDimensions() const { return getScale(); } virtual void setDimensions(const glm::vec3& value); @@ -242,6 +240,7 @@ public: using SpatiallyNestable::getQueryAACube; virtual AACube getQueryAACube(bool& success) const override; + const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index cc4ff2cf1c..10d851ec5a 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -55,6 +55,7 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { _parentKnowsMe = false; } }); + checkAndAdjustQueryAACube(); } Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const { @@ -139,6 +140,7 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { void SpatiallyNestable::setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; + checkAndAdjustQueryAACube(); } glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, @@ -776,7 +778,7 @@ void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) { return; } _queryAACube = queryAACube; - if (_queryAACube.getScale() > 0.0f) { + if (queryAACube.getScale() > 0.0f) { _queryAACubeSet = true; } } From 8799bf2d55484d6c52b7b1cc5523d1552971c176 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 11 Mar 2016 16:36:13 -0800 Subject: [PATCH 196/258] Alternative implementation, which only selects visible bestZone. --- .../src/EntityTreeRenderer.cpp | 117 ++++++++++-------- .../src/EntityTreeRenderer.h | 1 + 2 files changed, 67 insertions(+), 51 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 96e8d16767..e2bc093d48 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -157,6 +157,65 @@ void EntityTreeRenderer::update() { deleteReleasedModels(); } +bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(glm::vec3& avatarPosition, QVector* entitiesContainingAvatar) { + bool didUpdate = false; + float radius = 1.0f; // for now, assume 1 meter radius + QVector foundEntities; + + // find the entities near us + // don't let someone else change our tree while we search + _tree->withReadLock([&] { + std::static_pointer_cast(_tree)->findEntities(avatarPosition, radius, foundEntities); + + // Whenever you're in an intersection between zones, we will always choose the smallest zone. + auto oldBestZone = _bestZone; + _bestZone = nullptr; // NOTE: Is this what we want? + _bestZoneVolume = std::numeric_limits::max(); + + // create a list of entities that actually contain the avatar's position + foreach(EntityItemPointer entity, foundEntities) { + if (entity->contains(avatarPosition)) { + if (entitiesContainingAvatar) { + *entitiesContainingAvatar << entity->getEntityItemID(); + } + + // if this entity is a zone, use this time to determine the bestZone + if (entity->getType() == EntityTypes::Zone) { + if (!entity->getVisible()) { + qCDebug(entitiesrenderer) << "not visible"; + } + else { + float entityVolumeEstimate = entity->getVolumeEstimate(); + if (entityVolumeEstimate < _bestZoneVolume) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = std::dynamic_pointer_cast(entity); + } + else if (entityVolumeEstimate == _bestZoneVolume) { + if (!_bestZone) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = std::dynamic_pointer_cast(entity); + } + else { + // in the case of the volume being equal, we will use the + // EntityItemID to deterministically pick one entity over the other + if (entity->getEntityItemID() < _bestZone->getEntityItemID()) { + _bestZoneVolume = entityVolumeEstimate; + _bestZone = std::dynamic_pointer_cast(entity); + } + } + } + } + } + } + } + + if (_bestZone != oldBestZone) { + applyZonePropertiesToScene(_bestZone); + didUpdate = true; + } + }); + return didUpdate; +} bool EntityTreeRenderer::checkEnterLeaveEntities() { bool didUpdate = false; @@ -164,54 +223,8 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() { glm::vec3 avatarPosition = _viewState->getAvatarPosition(); if (avatarPosition != _lastAvatarPosition) { - float radius = 1.0f; // for now, assume 1 meter radius - QVector foundEntities; QVector entitiesContainingAvatar; - - // find the entities near us - // don't let someone else change our tree while we search - _tree->withReadLock([&] { - std::static_pointer_cast(_tree)->findEntities(avatarPosition, radius, foundEntities); - - // Whenever you're in an intersection between zones, we will always choose the smallest zone. - auto oldBestZone = _bestZone; - _bestZone = nullptr; // NOTE: Is this what we want? - _bestZoneVolume = std::numeric_limits::max(); - - // create a list of entities that actually contain the avatar's position - foreach(EntityItemPointer entity, foundEntities) { - if (entity->contains(avatarPosition)) { - entitiesContainingAvatar << entity->getEntityItemID(); - - // if this entity is a zone, use this time to determine the bestZone - if (entity->getType() == EntityTypes::Zone) { - float entityVolumeEstimate = entity->getVolumeEstimate(); - if (entityVolumeEstimate < _bestZoneVolume) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entity); - } else if (entityVolumeEstimate == _bestZoneVolume) { - if (!_bestZone) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entity); - } else { - // in the case of the volume being equal, we will use the - // EntityItemID to deterministically pick one entity over the other - if (entity->getEntityItemID() < _bestZone->getEntityItemID()) { - _bestZoneVolume = entityVolumeEstimate; - _bestZone = std::dynamic_pointer_cast(entity); - } - } - } - - } - } - } - - if (_bestZone != oldBestZone) { - applyZonePropertiesToScene(_bestZone); - didUpdate = true; - } - }); + didUpdate = findBestZoneAndMaybeContainingEntities(avatarPosition, &entitiesContainingAvatar); // Note: at this point we don't need to worry about the tree being locked, because we only deal with // EntityItemIDs from here. The callEntityScriptMethod() method is robust against attempting to call scripts @@ -234,6 +247,8 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() { } _currentEntitiesInside = entitiesContainingAvatar; _lastAvatarPosition = avatarPosition; + } else { + didUpdate = findBestZoneAndMaybeContainingEntities(avatarPosition, nullptr); } } return didUpdate; @@ -375,9 +390,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetSkyboxProperties().getURL(); } } - // Visibility does not effect other side effects such as ambient light or the selection of "best" zone. - // The skyStage backgroundMode is the hammer used (e.g., in Application.cpp) to control the visiblity of the sky box. - skyStage->setBackgroundMode(zone->getVisible() ? model::SunSkyStage::SKY_BOX : model::SunSkyStage::SKY_DOME); + skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); break; } @@ -873,7 +886,9 @@ void EntityTreeRenderer::updateZone(const EntityItemID& id) { _currentEntitiesInside << id; emit enterEntity(id); _entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity"); - _bestZone = std::dynamic_pointer_cast(zone); + if (zone->getVisible()) { + _bestZone = std::dynamic_pointer_cast(zone); + } } } if (_bestZone && _bestZone->getID() == id) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 5aadf7d299..b2a2d436c4 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -124,6 +124,7 @@ protected: private: void addEntityToScene(EntityItemPointer entity); + bool findBestZoneAndMaybeContainingEntities(glm::vec3& avatarPosition, QVector* entitiesContainingAvatar); void applyZonePropertiesToScene(std::shared_ptr zone); void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false); From 801f2b3f9f4ca5e8daf657c112334f5d7cd2cc45 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 16:38:39 -0800 Subject: [PATCH 197/258] add animated urchin --- .../Home/fishTank/createFishTank.js | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js index cd03b1efa2..79645b6e77 100644 --- a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js +++ b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js @@ -34,7 +34,15 @@ var DEBUG_COLOR = { blue: 255 } -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), 1 * TANK_WIDTH)); + +var centerVertical = { + x: 0, + y: 1, + z: 0 +} + +var upCenter = Vec3.sum(centerVertical, MyAvatar.position); +var center = Vec3.sum(upCenter, Vec3.multiply(Quat.getFront(MyAvatar.orientation), 2)); var TANK_POSITION = center; @@ -52,7 +60,7 @@ var TANK_BASE_DIMENSIONS = { z: 2.1936 }; -var BASE_VERTICAL_OFFSET = 0.42; +var BASE_VERTICAL_OFFSET = 0.47; var BUBBLE_SYSTEM_FORWARD_OFFSET = TANK_DIMENSIONS.x + 0.06; var BUBBLE_SYSTEM_LATERAL_OFFSET = 0.025; @@ -73,8 +81,8 @@ var URCHIN_LATERAL_OFFSET = -0.05; var URCHIN_VERTICAL_OFFSET = -0.12; -var URCHIN_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/Urchin.fbx'; - +var URCHIN_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; +var URCHIN_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; var URCHIN_DIMENSIONS = { x: 0.4, y: 0.4, @@ -308,10 +316,21 @@ function createUrchin() { var properties = { name: 'hifi-home-fishtank-urchin', type: 'Model', + animationURL: URCHIN_ANIMATION_URL, + animationIsPlaying: true, + animationFPS:15, + animationSettings: JSON.stringify({ + + hold: false, + loop: true, + running: true, + startAutomatically: true + }), parentID: fishTank, modelURL: URCHIN_MODEL_URL, position: finalPosition, shapeType: 'Sphere', + rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), dimensions: URCHIN_DIMENSIONS } From 68cc87298f208baf3fd152fa4381946b9b448ddb Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 16:39:58 -0800 Subject: [PATCH 198/258] cleanup --- .../DomainContent/Home/fishTank/createFishTank.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js index 79645b6e77..3c168fc668 100644 --- a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js +++ b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js @@ -318,9 +318,8 @@ function createUrchin() { type: 'Model', animationURL: URCHIN_ANIMATION_URL, animationIsPlaying: true, - animationFPS:15, + animationFPS: 15, animationSettings: JSON.stringify({ - hold: false, loop: true, running: true, From 8375de451790fbf4e7c37d5b849a1f10d5d253bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 17:32:24 -0800 Subject: [PATCH 199/258] make the ATPAssetMigrator hmd friendly and a little less brittle --- interface/src/assets/ATPAssetMigrator.cpp | 115 +++++++++----- interface/src/assets/ATPAssetMigrator.h | 7 +- interface/src/ui/AssetUploadDialogFactory.cpp | 143 ------------------ interface/src/ui/AssetUploadDialogFactory.h | 44 ------ 4 files changed, 85 insertions(+), 224 deletions(-) delete mode 100644 interface/src/ui/AssetUploadDialogFactory.cpp delete mode 100644 interface/src/ui/AssetUploadDialogFactory.h diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index e9327924a9..8da3c79999 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -24,9 +24,9 @@ #include #include #include +#include #include "OffscreenUi.h" -#include "../ui/AssetUploadDialogFactory.h" Q_DECLARE_LOGGING_CATEGORY(asset_migrator); Q_LOGGING_CATEGORY(asset_migrator, "hf.asset_migrator"); @@ -41,15 +41,14 @@ static const QString MODEL_URL_KEY = "modelURL"; static const QString MESSAGE_BOX_TITLE = "ATP Asset Migration"; void ATPAssetMigrator::loadEntityServerFile() { - auto filename = QFileDialog::getOpenFileName(_dialogParent, "Select an entity-server content file to migrate", - QString(), QString("Entity-Server Content (*.gz)")); + auto filename = OffscreenUi::getOpenFileName(_dialogParent, tr("Select an entity-server content file to migrate"), QString(), tr("Entity-Server Content (*.gz)")); if (!filename.isEmpty()) { qCDebug(asset_migrator) << "Selected filename for ATP asset migration: " << filename; static const QString MIGRATION_CONFIRMATION_TEXT { - "The ATP Asset Migration process will scan the selected entity-server file, upload discovered resources to the"\ - " current asset-server and then save a new entity-server file with the ATP URLs.\n\nAre you ready to"\ + "The ATP Asset Migration process will scan the selected entity-server file,\nupload discovered resources to the"\ + " current asset-server\nand then save a new entity-server file with the ATP URLs.\n\nAre you ready to"\ " continue?\n\nMake sure you are connected to the right domain." }; @@ -108,16 +107,17 @@ void ATPAssetMigrator::loadEntityServerFile() { if (request->getResult() == ResourceRequest::Success) { migrateResource(request); } else { - OffscreenUi::warning(_dialogParent, "Error", - QString("Could not retrieve asset at %1").arg(modelURL.toString())); + ++_errorCount; + _pendingReplacements.remove(modelURL); + qWarning() << "Could not retrieve asset at" << modelURL.toString(); } request->deleteLater(); }); request->send(); } else { - OffscreenUi::warning(_dialogParent, "Error", - QString("Could not create request for asset at %1").arg(modelURL.toString())); + ++_errorCount; + qWarning() << "Count not create request for asset at" << modelURL.toString(); } } else { @@ -140,8 +140,6 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { // use an asset client to upload the asset auto assetClient = DependencyManager::get(); - QFileInfo assetInfo { request->getUrl().fileName() }; - auto upload = assetClient->createUpload(request->getData()); // add this URL to our hash of AssetUpload to original URL @@ -157,41 +155,78 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { } void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& hash) { + // remove this modelURL from the key for the AssetUpload pointer + auto modelURL = _originalURLs.take(upload); + if (upload->getError() == AssetUpload::NoError) { - const auto& modelURL = _originalURLs[upload]; - + // use the path of the modelURL to add a mapping in the Asset Server + auto assetClient = DependencyManager::get(); + auto setMappingRequest = assetClient->createSetMappingRequest(modelURL.path(), hash); + + connect(setMappingRequest, &SetMappingRequest::finished, this, &ATPAssetMigrator::setMappingFinished); + + // add this modelURL with the key for the SetMappingRequest pointer + _originalURLs[setMappingRequest] = modelURL; + + setMappingRequest->start(); + } else { + // this is a fail for this modelURL, remove it from pending replacements + _pendingReplacements.remove(modelURL); + + ++_errorCount; + qWarning() << "Failed to upload" << modelURL << "- error was" << upload->getErrorString(); + } + + checkIfFinished(); + + upload->deleteLater(); +} + +void ATPAssetMigrator::setMappingFinished(SetMappingRequest* request) { + // take the modelURL for this SetMappingRequest + auto modelURL = _originalURLs.take(request); + + if (request->getError() == MappingRequest::NoError) { + // successfully uploaded asset - make any required replacements found in the pending replacements auto values = _pendingReplacements.values(modelURL); - - - QString atpURL = getATPUrl(hash).toString(); - + + QString atpURL = QString("atp:%1").arg(request->getPath()); + for (auto value : values) { // replace the modelURL in this QJsonValueRef with the hash QJsonObject valueObject = value.toObject(); valueObject[MODEL_URL_KEY] = atpURL; value = valueObject; } - + // add this URL to our list of uploaded assets _uploadedAssets.insert(modelURL, atpURL); - + // pull the replaced models from _pendingReplacements _pendingReplacements.remove(modelURL); - - // are we out of pending replacements? if so it is time to save the entity-server file - if (_doneReading && _pendingReplacements.empty()) { - saveEntityServerFile(); - - // reset after the attempted save, success or fail - reset(); - } } else { - AssetUploadDialogFactory::showErrorDialog(upload, _dialogParent); + // this is a fail for this modelURL, remove it from pending replacements + _pendingReplacements.remove(modelURL); + + ++_errorCount; + qWarning() << "Error setting mapping for" << modelURL << "- error was " << request->getErrorString(); + } + + checkIfFinished(); + + request->deleteLater(); +} + +void ATPAssetMigrator::checkIfFinished() { + // are we out of pending replacements? if so it is time to save the entity-server file + if (_doneReading && _pendingReplacements.empty()) { + saveEntityServerFile(); + + // reset after the attempted save, success or fail + reset(); } - - upload->deleteLater(); } bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) { @@ -200,8 +235,8 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) { if (!hasAskedForCompleteMigration) { // this is the first resource migration - ask the user if they just want to migrate everything - static const QString COMPLETE_MIGRATION_TEXT { "Do you want to migrate all assets found in this entity-server file?\n\n"\ - "Select \"Yes\" to upload all discovered assets to the current asset-server immediately.\n\n"\ + static const QString COMPLETE_MIGRATION_TEXT { "Do you want to migrate all assets found in this entity-server file?\n"\ + "Select \"Yes\" to upload all discovered assets to the current asset-server immediately.\n"\ "Select \"No\" to be prompted for each discovered asset." }; @@ -228,7 +263,7 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) { void ATPAssetMigrator::saveEntityServerFile() { // show a dialog to ask the user where they want to save the file - QString saveName = QFileDialog::getSaveFileName(_dialogParent, "Save Migrated Entities File"); + QString saveName = OffscreenUi::getSaveFileName(_dialogParent, "Save Migrated Entities File"); QFile saveFile { saveName }; @@ -243,9 +278,16 @@ void ATPAssetMigrator::saveEntityServerFile() { saveFile.write(jsonDataForFile); saveFile.close(); - - QMessageBox::information(_dialogParent, "Success", - QString("Your new entities file has been saved at %1").arg(saveName)); + + QString infoMessage = QString("Your new entities file has been saved at\n%1.").arg(saveName); + + if (_errorCount > 0) { + infoMessage += QString("\nThere were %1 models that could not be migrated.\n").arg(_errorCount); + infoMessage += "Check the warnings in your log for details.\n"; + infoMessage += "You can re-attempt migration on those models\nby restarting this process with the newly saved file."; + } + + OffscreenUi::information(_dialogParent, "Success", infoMessage); } else { OffscreenUi::warning(_dialogParent, "Error", "Could not gzip JSON data for new entities file."); } @@ -263,4 +305,5 @@ void ATPAssetMigrator::reset() { _uploadedAssets.clear(); _originalURLs.clear(); _ignoredUrls.clear(); + _errorCount = 0; } diff --git a/interface/src/assets/ATPAssetMigrator.h b/interface/src/assets/ATPAssetMigrator.h index 454eb1eac1..8e20c5ab7a 100644 --- a/interface/src/assets/ATPAssetMigrator.h +++ b/interface/src/assets/ATPAssetMigrator.h @@ -21,6 +21,7 @@ class AssetUpload; class ResourceRequest; +class SetMappingRequest; class ATPAssetMigrator : public QObject { Q_OBJECT @@ -32,8 +33,11 @@ public slots: void loadEntityServerFile(); private slots: void assetUploadFinished(AssetUpload* upload, const QString& hash); + void setMappingFinished(SetMappingRequest* request); private: void migrateResource(ResourceRequest* request); + + void checkIfFinished(); void saveEntityServerFile(); void reset(); @@ -47,8 +51,9 @@ private: QMultiHash _pendingReplacements; QHash _uploadedAssets; - QHash _originalURLs; + QHash _originalURLs; QSet _ignoredUrls; + int _errorCount { 0 }; }; diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp deleted file mode 100644 index 7b2da4c83b..0000000000 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// -// AssetUploadDialogFactory.cpp -// interface/src/ui -// -// Created by Stephen Birarda on 2015-08-26. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "AssetUploadDialogFactory.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() { - static AssetUploadDialogFactory staticInstance; - return staticInstance; -} - - - -void AssetUploadDialogFactory::showDialog() { - auto nodeList = DependencyManager::get(); - - if (nodeList->getThisNodeCanRez()) { - auto filename = QFileDialog::getOpenFileName(_dialogParent, "Select a file to upload"); - - if (!filename.isEmpty()) { - qDebug() << "Selected filename for upload to asset-server: " << filename; - - auto assetClient = DependencyManager::get(); - auto upload = assetClient->createUpload(filename); - - // connect to the finished signal so we know when the AssetUpload is done - QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); - - // start the upload now - upload->start(); - } - } else { - // we don't have permission to upload to asset server in this domain - show the permission denied error - showErrorDialog(nullptr, _dialogParent, AssetUpload::PERMISSION_DENIED_ERROR); - } - -} - -void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const QString& hash) { - if (upload->getError() == AssetUpload::NoError) { - // show message box for successful upload, with copiable text for ATP hash - QDialog* hashCopyDialog = new QDialog(_dialogParent); - - // delete the dialog on close - hashCopyDialog->setAttribute(Qt::WA_DeleteOnClose); - - // set the window title - hashCopyDialog->setWindowTitle(tr("Successful Asset Upload")); - - // setup a layout for the contents of the dialog - QVBoxLayout* boxLayout = new QVBoxLayout; - - // set the label text (this shows above the text box) - QLabel* lineEditLabel = new QLabel; - lineEditLabel->setText(QString("ATP URL for %1").arg(QFileInfo(upload->getFilename()).fileName())); - - // setup the line edit to hold the copiable text - QLineEdit* lineEdit = new QLineEdit; - - QString atpURL = QString("%1:%2").arg(URL_SCHEME_ATP).arg(hash); - - // set the ATP URL as the text value so it's copiable - lineEdit->insert(atpURL); - - // figure out what size this line edit should be using font metrics - QFontMetrics textMetrics { lineEdit->font() }; - - // set the fixed width on the line edit - // pad it by 10 to cover the border and some extra space on the right side (for clicking) - static const int LINE_EDIT_RIGHT_PADDING { 10 }; - - lineEdit->setFixedWidth(textMetrics.width(atpURL) + LINE_EDIT_RIGHT_PADDING ); - - // left align the ATP URL line edit - lineEdit->home(true); - - // add the label and line edit to the dialog - boxLayout->addWidget(lineEditLabel); - boxLayout->addWidget(lineEdit); - - // setup an OK button to close the dialog - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); - connect(buttonBox, &QDialogButtonBox::accepted, hashCopyDialog, &QDialog::close); - boxLayout->addWidget(buttonBox); - - // set the new layout on the dialog - hashCopyDialog->setLayout(boxLayout); - - // show the new dialog - hashCopyDialog->show(); - } else { - // display a message box with the error - showErrorDialog(upload, _dialogParent); - } - - upload->deleteLater(); -} - -void AssetUploadDialogFactory::showErrorDialog(AssetUpload* upload, QWidget* dialogParent, const QString& overrideMessage) { - QString filename; - - if (upload) { - filename = QFileInfo { upload->getFilename() }.fileName(); - } - - QString errorMessage = overrideMessage; - - if (errorMessage.isEmpty() && upload) { - errorMessage = upload->getErrorString(); - } - - QString dialogMessage; - - if (upload) { - dialogMessage += QString("Failed to upload %1.\n\n").arg(filename); - } - - dialogMessage += errorMessage; - - OffscreenUi::warning(dialogParent, "Failed Upload", dialogMessage); -} diff --git a/interface/src/ui/AssetUploadDialogFactory.h b/interface/src/ui/AssetUploadDialogFactory.h deleted file mode 100644 index fe3ecf5dc4..0000000000 --- a/interface/src/ui/AssetUploadDialogFactory.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// AssetUploadDialogFactory.h -// interface/src/ui -// -// Created by Stephen Birarda on 2015-08-26. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once - -#ifndef hifi_AssetUploadDialogFactory_h -#define hifi_AssetUploadDialogFactory_h - -#include - -class AssetUpload; - -class AssetUploadDialogFactory : public QObject { - Q_OBJECT -public: - AssetUploadDialogFactory(const AssetUploadDialogFactory& other) = delete; - AssetUploadDialogFactory& operator=(const AssetUploadDialogFactory& rhs) = delete; - - static AssetUploadDialogFactory& getInstance(); - static void showErrorDialog(AssetUpload* upload, QWidget* dialogParent, const QString& overrideMessage = QString()); - - void setDialogParent(QWidget* dialogParent) { _dialogParent = dialogParent; } - -public slots: - void showDialog(); - void handleUploadFinished(AssetUpload* upload, const QString& hash); - -private: - AssetUploadDialogFactory() = default; - - - - QWidget* _dialogParent { nullptr }; -}; - -#endif // hifi_AssetUploadDialogFactory_h From 76e547498d8e356d0a81169b5c8f09733d19e612 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Mar 2016 18:02:06 -0800 Subject: [PATCH 200/258] support compound shape URLs in ATPAssetMigrator --- interface/src/assets/ATPAssetMigrator.cpp | 150 +++++++++++++--------- interface/src/assets/ATPAssetMigrator.h | 6 +- 2 files changed, 91 insertions(+), 65 deletions(-) diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index 8da3c79999..e0e9d5a73a 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -38,6 +38,7 @@ ATPAssetMigrator& ATPAssetMigrator::getInstance() { static const QString ENTITIES_OBJECT_KEY = "Entities"; static const QString MODEL_URL_KEY = "modelURL"; +static const QString COMPOUND_SHAPE_URL_KEY = "compoundShapeURL"; static const QString MESSAGE_BOX_TITLE = "ATP Asset Migration"; void ATPAssetMigrator::loadEntityServerFile() { @@ -76,58 +77,75 @@ void ATPAssetMigrator::loadEntityServerFile() { for (auto jsonValue : _entitiesArray) { QJsonObject entityObject = jsonValue.toObject(); QString modelURLString = entityObject.value(MODEL_URL_KEY).toString(); - - if (!modelURLString.isEmpty()) { - QUrl modelURL = QUrl(modelURLString); - - if (!_ignoredUrls.contains(modelURL) - && (modelURL.scheme() == URL_SCHEME_HTTP || modelURL.scheme() == URL_SCHEME_HTTPS - || modelURL.scheme() == URL_SCHEME_FILE || modelURL.scheme() == URL_SCHEME_FTP)) { - - if (_pendingReplacements.contains(modelURL)) { - // we already have a request out for this asset, just store the QJsonValueRef - // so we can do the hash replacement when the request comes back - _pendingReplacements.insert(modelURL, jsonValue); - } else if (_uploadedAssets.contains(modelURL)) { - // we already have a hash for this asset - // so just do the replacement immediately - entityObject[MODEL_URL_KEY] = _uploadedAssets.value(modelURL).toString(); - jsonValue = entityObject; - } else if (wantsToMigrateResource(modelURL)) { - auto request = ResourceManager::createResourceRequest(this, modelURL); - - if (request) { - qCDebug(asset_migrator) << "Requesting" << modelURL << "for ATP asset migration"; - - // add this combination of QUrl and QJsonValueRef to our multi hash so we can change the URL - // to an ATP one once ready - _pendingReplacements.insert(modelURL, jsonValue); - - connect(request, &ResourceRequest::finished, this, [=]() { - if (request->getResult() == ResourceRequest::Success) { - migrateResource(request); + QString compoundURLString = entityObject.value(COMPOUND_SHAPE_URL_KEY).toString(); + + for (int i = 0; i < 2; ++i) { + bool isModelURL = (i == 0); + quint8 replacementType = i; + auto migrationURLString = (isModelURL) ? modelURLString : compoundURLString; + + if (!migrationURLString.isEmpty()) { + QUrl migrationURL = QUrl(migrationURLString); + + if (!_ignoredUrls.contains(migrationURL) + && (migrationURL.scheme() == URL_SCHEME_HTTP || migrationURL.scheme() == URL_SCHEME_HTTPS + || migrationURL.scheme() == URL_SCHEME_FILE || migrationURL.scheme() == URL_SCHEME_FTP)) { + + if (_pendingReplacements.contains(migrationURL)) { + // we already have a request out for this asset, just store the QJsonValueRef + // so we can do the hash replacement when the request comes back + _pendingReplacements.insert(migrationURL, { jsonValue, replacementType }); + } else if (_uploadedAssets.contains(migrationURL)) { + // we already have a hash for this asset + // so just do the replacement immediately + if (isModelURL) { + entityObject[MODEL_URL_KEY] = _uploadedAssets.value(migrationURL).toString(); + } else { + entityObject[COMPOUND_SHAPE_URL_KEY] = _uploadedAssets.value(migrationURL).toString(); + } + + jsonValue = entityObject; + } else if (wantsToMigrateResource(migrationURL)) { + auto request = ResourceManager::createResourceRequest(this, migrationURL); + + if (request) { + qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration"; + + // add this combination of QUrl and QJsonValueRef to our multi hash so we can change the URL + // to an ATP one once ready + _pendingReplacements.insert(migrationURL, { jsonValue, (isModelURL ? 0 : 1)}); + + connect(request, &ResourceRequest::finished, this, [=]() { + if (request->getResult() == ResourceRequest::Success) { + migrateResource(request); + } else { + ++_errorCount; + _pendingReplacements.remove(migrationURL); + qWarning() << "Could not retrieve asset at" << migrationURL.toString(); + + checkIfFinished(); + } + request->deleteLater(); + }); + + request->send(); } else { ++_errorCount; - _pendingReplacements.remove(modelURL); - qWarning() << "Could not retrieve asset at" << modelURL.toString(); + qWarning() << "Count not create request for asset at" << migrationURL.toString(); } - request->deleteLater(); - }); - - request->send(); - } else { - ++_errorCount; - qWarning() << "Count not create request for asset at" << modelURL.toString(); + + } else { + _ignoredUrls.insert(migrationURL); + } } - - } else { - _ignoredUrls.insert(modelURL); - } } } + } _doneReading = true; + + checkIfFinished(); } else { OffscreenUi::warning(_dialogParent, "Error", @@ -155,27 +173,27 @@ void ATPAssetMigrator::migrateResource(ResourceRequest* request) { } void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& hash) { - // remove this modelURL from the key for the AssetUpload pointer - auto modelURL = _originalURLs.take(upload); + // remove this migrationURL from the key for the AssetUpload pointer + auto migrationURL = _originalURLs.take(upload); if (upload->getError() == AssetUpload::NoError) { - // use the path of the modelURL to add a mapping in the Asset Server + // use the path of the migrationURL to add a mapping in the Asset Server auto assetClient = DependencyManager::get(); - auto setMappingRequest = assetClient->createSetMappingRequest(modelURL.path(), hash); + auto setMappingRequest = assetClient->createSetMappingRequest(migrationURL.path(), hash); connect(setMappingRequest, &SetMappingRequest::finished, this, &ATPAssetMigrator::setMappingFinished); - // add this modelURL with the key for the SetMappingRequest pointer - _originalURLs[setMappingRequest] = modelURL; + // add this migrationURL with the key for the SetMappingRequest pointer + _originalURLs[setMappingRequest] = migrationURL; setMappingRequest->start(); } else { // this is a fail for this modelURL, remove it from pending replacements - _pendingReplacements.remove(modelURL); + _pendingReplacements.remove(migrationURL); ++_errorCount; - qWarning() << "Failed to upload" << modelURL << "- error was" << upload->getErrorString(); + qWarning() << "Failed to upload" << migrationURL << "- error was" << upload->getErrorString(); } checkIfFinished(); @@ -184,34 +202,40 @@ void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& h } void ATPAssetMigrator::setMappingFinished(SetMappingRequest* request) { - // take the modelURL for this SetMappingRequest - auto modelURL = _originalURLs.take(request); + // take the migrationURL for this SetMappingRequest + auto migrationURL = _originalURLs.take(request); if (request->getError() == MappingRequest::NoError) { // successfully uploaded asset - make any required replacements found in the pending replacements - auto values = _pendingReplacements.values(modelURL); + auto values = _pendingReplacements.values(migrationURL); QString atpURL = QString("atp:%1").arg(request->getPath()); for (auto value : values) { // replace the modelURL in this QJsonValueRef with the hash - QJsonObject valueObject = value.toObject(); - valueObject[MODEL_URL_KEY] = atpURL; - value = valueObject; + QJsonObject valueObject = value.first.toObject(); + + if (value.second == 0) { + valueObject[MODEL_URL_KEY] = atpURL; + } else { + valueObject[COMPOUND_SHAPE_URL_KEY] = atpURL; + } + + value.first = valueObject; } // add this URL to our list of uploaded assets - _uploadedAssets.insert(modelURL, atpURL); + _uploadedAssets.insert(migrationURL, atpURL); - // pull the replaced models from _pendingReplacements - _pendingReplacements.remove(modelURL); + // pull the replaced urls from _pendingReplacements + _pendingReplacements.remove(migrationURL); } else { - // this is a fail for this modelURL, remove it from pending replacements - _pendingReplacements.remove(modelURL); + // this is a fail for this migrationURL, remove it from pending replacements + _pendingReplacements.remove(migrationURL); ++_errorCount; - qWarning() << "Error setting mapping for" << modelURL << "- error was " << request->getErrorString(); + qWarning() << "Error setting mapping for" << migrationURL << "- error was " << request->getErrorString(); } checkIfFinished(); diff --git a/interface/src/assets/ATPAssetMigrator.h b/interface/src/assets/ATPAssetMigrator.h index 8e20c5ab7a..c1becb9c7f 100644 --- a/interface/src/assets/ATPAssetMigrator.h +++ b/interface/src/assets/ATPAssetMigrator.h @@ -48,8 +48,10 @@ private: QJsonArray _entitiesArray; bool _doneReading { false }; - - QMultiHash _pendingReplacements; + + using JSONTypePair = std::pair; + + QMultiHash> _pendingReplacements; QHash _uploadedAssets; QHash _originalURLs; QSet _ignoredUrls; From 3cf32b17be236a22ca0b672ccc48e0e64527daa2 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 11 Mar 2016 18:52:02 -0800 Subject: [PATCH 201/258] Trying to fix the jittering issue, foound an extra matrix inversion that could be the source --- libraries/gpu/src/gpu/Context.cpp | 18 ++++--- libraries/gpu/src/gpu/Context.h | 6 +-- libraries/gpu/src/gpu/GLBackendTransform.cpp | 5 +- libraries/gpu/src/gpu/Transform.slh | 54 +++++++++++--------- 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index e1dc94fcd7..013433102a 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -74,9 +74,11 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons _backend->downloadFramebuffer(srcFramebuffer, region, destImage); } -const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived() const { +const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const { _projectionInverse = glm::inverse(_projection); - _viewInverse = glm::inverse(_view); + // _viewInverse = glm::inverse(_view); + xformView.getMatrix(_viewInverse); + _view = glm::inverse(_viewInverse); Mat4 viewUntranslated = _view; viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f); @@ -84,16 +86,18 @@ const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived() con return *this; } -Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const StereoState& _stereo) const { +Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const StereoState& _stereo, const Transform& xformView) const { TransformCamera result = *this; + Transform offsetTransform = xformView; if (!_stereo._skybox) { result._view = _stereo._eyeViews[eye] * result._view; + offsetTransform.postTranslate(-Vec3(_stereo._eyeViews[eye][3])); } else { - glm::mat4 skyboxView = _stereo._eyeViews[eye]; - skyboxView[3] = vec4(0, 0, 0, 1); - result._view = skyboxView * result._view; + // glm::mat4 skyboxView = _stereo._eyeViews[eye]; + // skyboxView[3] = vec4(0, 0, 0, 1); + // result._view = skyboxView * result._view; } result._projection = _stereo._eyeProjections[eye]; - result.recomputeDerived(); + result.recomputeDerived(xformView); return result; } diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index dceb606f20..d584f54acc 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -79,15 +79,15 @@ public: // UBO class... layout MUST match the layout in TransformCamera.slh class TransformCamera { public: - Mat4 _view; + mutable Mat4 _view; mutable Mat4 _viewInverse; mutable Mat4 _projectionViewUntranslated; Mat4 _projection; mutable Mat4 _projectionInverse; Vec4 _viewport; // Public value is int but float in the shader to stay in floats for all the transform computations. - const Backend::TransformCamera& recomputeDerived() const; - TransformCamera getEyeCamera(int eye, const StereoState& stereo) const; + const Backend::TransformCamera& recomputeDerived(const Transform& xformView) const; + TransformCamera getEyeCamera(int eye, const StereoState& stereo, const Transform& xformView) const; }; diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index d5bcfa3321..19cb7fb2a9 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -105,6 +105,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo } if (_invalidView) { + // This is when the _view matrix gets assigned _view.getInverseMatrix(_camera._view); } @@ -113,11 +114,11 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo if (stereo._enable) { _cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); for (int i = 0; i < 2; ++i) { - _cameras.push_back(_camera.getEyeCamera(i, stereo)); + _cameras.push_back(_camera.getEyeCamera(i, stereo, _view)); } } else { _cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); - _cameras.push_back(_camera.recomputeDerived()); + _cameras.push_back(_camera.recomputeDerived(_view)); } } diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index ea5ee06a7b..e4f8f5dd87 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -76,24 +76,40 @@ TransformObject getTransformObject() { <$viewport$> = <$cameraTransform$>._viewport; <@endfunc@> -<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> - - { // transformModelToClipPos - vec4 _eyepos = (<$objectTransform$>._model * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0); - <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos; +<@func transformModelToEyeWorldAlignedPos(cameraTransform, objectTransform, modelPos, eyeWorldAlignedPos)@> + + { // _transformModelToEyeWorldAlignedPos + highp mat4 _mv = <$objectTransform$>._model; + _mv[3].xyz -= <$cameraTransform$>._viewInverse[3].xyz; + highp vec4 _eyeWApos = (_mv * <$modelPos$>); + <$eyeWorldAlignedPos$> = _eyeWApos; } <@endfunc@> -<@func $transformModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@> - +<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> { // transformModelToClipPos - vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); - <$eyePos$> = (<$cameraTransform$>._view * _worldpos); - vec4 _eyepos =(<$objectTransform$>._model * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0); - <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos; - // <$eyePos$> = (<$cameraTransform$>._projectionInverse * <$clipPos$>); + vec4 eyeWAPos; + <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> + + <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; + } +<@endfunc@> + +<@func transformModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@> + { // transformModelToEyeAndClipPos + vec4 eyeWAPos; + <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> + + <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; + <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); + } +<@endfunc@> + +<@func transformModelToEyePos(cameraTransform, objectTransform, modelPos, eyePos)@> + { // transformModelToEyePos + vec4 eyeWAPos; + <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> + <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); } <@endfunc@> @@ -103,6 +119,7 @@ TransformObject getTransformObject() { } <@endfunc@> + <@func transformModelToEyeDir(cameraTransform, objectTransform, modelDir, eyeDir)@> { // transformModelToEyeDir vec3 mr0 = vec3(<$objectTransform$>._modelInverse[0].x, <$objectTransform$>._modelInverse[1].x, <$objectTransform$>._modelInverse[2].x); @@ -129,15 +146,6 @@ TransformObject getTransformObject() { } <@endfunc@> -<@func $transformModelToEyePos(cameraTransform, objectTransform, modelPos, eyePos)@> - - { // transformModelToEyePos - vec4 _worldpos = (<$objectTransform$>._model * vec4(<$modelPos$>.xyz, 1.0)); - <$eyePos$> = (<$cameraTransform$>._view * _worldpos); - } -<@endfunc@> - <@func transformEyeToClipPos(cameraTransform, eyePos, clipPos)@> { // transformEyeToClipPos <$clipPos$> = <$cameraTransform$>._projection * vec4(<$eyePos$>.xyz, 1.0); From cecebc9ae499ea6f3136620e6d45c683b7c0792e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 22:01:01 -0800 Subject: [PATCH 202/258] add example --- examples/data_visualization/photo_sphere.js | 60 +++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/data_visualization/photo_sphere.js diff --git a/examples/data_visualization/photo_sphere.js b/examples/data_visualization/photo_sphere.js new file mode 100644 index 0000000000..8ea599d4f9 --- /dev/null +++ b/examples/data_visualization/photo_sphere.js @@ -0,0 +1,60 @@ +// photo_sphere.js +// +// Created by James B. Pollack on 3/11/2015 +// Copyright 2016 High Fidelity, Inc. +// +// This script creates a photo sphere around you. +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var photoSphere, light;; + +//equirectangular +var url = 'http://hifi-content.s3.amazonaws.com/james/projection_objects/IMG_9167.JPG'; + +var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/projection_objects/photosphere2.fbx'; + +function createPhotoSphere() { + + var textureString = 'photo:"' + url + '"' + print('ADDING TEXTURE:: ' + textureString); + var properties = { + type: 'Model', + modelURL: MODEL_URL, + name: 'hifi-photo-sphere', + dimensions: { + x: 32, + y: 32, + z: 32 + }, + position: MyAvatar.position, + textures: textureString + } + photoSphere = Entities.addEntity(properties); +} + +function createLight() { + var properties = { + name: 'hifi-photo-sphere-light', + type: 'Light', + dimensions: { + x: 36, + y: 36, + z: 36, + }, + intensity: 4.0, + falloffRadius: 22, + position: MyAvatar.position + } + light = Entities.addEntity(properties); +} + +function cleanup() { + Entities.deleteEntity(photoSphere); + Entities.deleteEntity(light); +} + +Script.scriptEnding.connect(cleanup); +createPhotoSphere(); +createLight(); \ No newline at end of file From b0109133c0af3f95370177192ba1c25fa87f7ff5 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 22:02:49 -0800 Subject: [PATCH 203/258] add git handle --- examples/data_visualization/photo_sphere.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/data_visualization/photo_sphere.js b/examples/data_visualization/photo_sphere.js index 8ea599d4f9..d8be423bd7 100644 --- a/examples/data_visualization/photo_sphere.js +++ b/examples/data_visualization/photo_sphere.js @@ -1,6 +1,6 @@ // photo_sphere.js // -// Created by James B. Pollack on 3/11/2015 +// Created by James B. Pollack @imgntn on 3/11/2015 // Copyright 2016 High Fidelity, Inc. // // This script creates a photo sphere around you. @@ -18,7 +18,7 @@ var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/projection_objects/p function createPhotoSphere() { var textureString = 'photo:"' + url + '"' - print('ADDING TEXTURE:: ' + textureString); + var properties = { type: 'Model', modelURL: MODEL_URL, From f7c6725f6319ad85292eac1c809912d84f84ba1b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 12 Mar 2016 23:24:52 +1300 Subject: [PATCH 204/258] Improve text3d rendering --- libraries/render-utils/src/sdf_text3D.slf | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index 1e11cd984d..854221a5cf 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -21,12 +21,10 @@ in vec3 _normal; in vec2 _texCoord0; const float gamma = 2.2; -const float smoothing = 256.0; +const float smoothing = 32.0; const float interiorCutoff = 0.8; const float outlineExpansion = 0.2; - - void main() { // retrieve signed distance float sdf = texture(Font, _texCoord0).g; From f1992af38e3d682719a3eaf10c1048848794d737 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 12 Mar 2016 10:13:13 -0800 Subject: [PATCH 205/258] started to add grabbable psuedo properties to edit.js --- examples/attachedEntitiesManager.js | 1 - examples/controllers/handControllerGrab.js | 8 +-- examples/html/entityProperties.html | 60 +++++++++++++++++++--- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/examples/attachedEntitiesManager.js b/examples/attachedEntitiesManager.js index 4dda76f4df..ef85f8cb98 100644 --- a/examples/attachedEntitiesManager.js +++ b/examples/attachedEntitiesManager.js @@ -213,7 +213,6 @@ function AttachedEntitiesManager() { var props = Entities.getEntityProperties(entityID); if (props.parentID == MyAvatar.sessionUUID) { grabData = getEntityCustomData('grabKey', entityID, {}); - grabbableData = getEntityCustomData('grabbableKey', entityID, {}); var wearableData = getEntityCustomData('wearable', entityID, DEFAULT_WEARABLE_DATA); var currentJointName = MyAvatar.getJointNames()[props.parentJointIndex]; wearableData.joints[currentJointName] = [props.localPosition, props.localRotation]; diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 964fca4136..43c18da72d 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1006,7 +1006,7 @@ function MyController(hand) { // else this thing isn't physical. grab it by reparenting it (but not if we've already // grabbed it). - if (grabbableData.refCount < 1) { + if (refCount < 1) { this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP); return; } else { @@ -1120,7 +1120,6 @@ function MyController(hand) { var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && this.hasPresetOffsets()) { @@ -1307,7 +1306,6 @@ function MyController(hand) { this.nearGrabbing = function() { var now = Date.now(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); @@ -1330,10 +1328,9 @@ function MyController(hand) { var handRotation = (this.hand === RIGHT_HAND) ? MyAvatar.getRightPalmRotation() : MyAvatar.getLeftPalmRotation(); var handPosition = this.getHandPosition(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - var hasPresetPosition = false; if (this.state != STATE_NEAR_GRABBING && this.hasPresetOffsets()) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); // if an object is "equipped" and has a predefined offset, use it. this.ignoreIK = grabbableData.ignoreIK ? grabbableData.ignoreIK : false; this.offsetPosition = this.getPresetPosition(); @@ -1676,7 +1673,6 @@ function MyController(hand) { }; this.activateEntity = function(entityID, grabbedProperties, wasLoaded) { - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); var now = Date.now(); diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 1101a08acb..92df997ac2 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -243,6 +243,21 @@ } + function createUserDataChanger(groupName, keyName, propertyElement, userData) { + return function() { + var properties = {}; + // // this.checked + // properties['userData'] = ... JSON.stringify (...) + // EventBridge.emitWebEvent( + // JSON.stringify({ + // type: "update", + // properties: properties, + // }) + // ); + } + }; + + function loaded() { openEventBridge(function() { var allSections = []; @@ -305,6 +320,11 @@ var elCollideMyAvatar = document.getElementById("property-collide-myAvatar"); var elCollideOtherAvatar = document.getElementById("property-collide-otherAvatar"); var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); + + var elGrabbable = document.getElementById("property-grabbable" ); + var elWantsTrigger = document.getElementById("property-wants-trigger" ); + var elIgnoreIK = document.getElementById("property-ignore-ik" ); + var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); var elScriptTimestamp = document.getElementById("property-script-timestamp"); @@ -408,7 +428,7 @@ var elXTextureURL = document.getElementById("property-x-texture-url"); var elYTextureURL = document.getElementById("property-y-texture-url"); var elZTextureURL = document.getElementById("property-z-texture-url"); - + var elPreviewCameraButton = document.getElementById("preview-camera-button"); if (window.EventBridge !== undefined) { @@ -518,13 +538,15 @@ elCollisionless.checked = properties.collisionless; elDynamic.checked = properties.dynamic; - elCollideStatic.checked = properties.collidesWith.indexOf("static") > -1; elCollideKinematic.checked = properties.collidesWith.indexOf("kinematic") > -1; elCollideDynamic.checked = properties.collidesWith.indexOf("dynamic") > -1; elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; + elGrabbable.checked = properties.collidesWith.indexOf("grabbable") > -1; + elWantsTrigger.checked = properties.collidesWith.indexOf("wantsTrigger") > -1; + elIgnoreIK.checked = properties.collidesWith.indexOf("ignoreIK") > -1; elCollisionSoundURL.value = properties.collisionSoundURL; elLifetime.value = properties.lifetime; @@ -737,9 +759,6 @@ elCollisionless.addEventListener('change', createEmitCheckedPropertyUpdateFunction('collisionless')); elDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('dynamic')); - - - elCollideDynamic.addEventListener('change', function() { updateCheckedSubProperty("collidesWith", properties.collidesWith, elCollideDynamic, 'dynamic'); }); @@ -758,6 +777,12 @@ updateCheckedSubProperty("collidesWith", properties.collidesWith, elCollideOtherAvatar, 'otherAvatar'); }); + elGrabbable.addEventListener('change', createUserDataChanger("grabbableKey", "grabbable", + elGrabbable, properties.userData)); + elWantsTrigger.addEventListener('change', createUserDataChanger("grabbableKey", "wantsTrigger", + elWantsTrigger, properties.userData)); + elIgnoreIK.addEventListener('change', createUserDataChanger("grabbableKey", "ignoreIK", + elIgnoreIK, properties.userData)); elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); @@ -954,7 +979,7 @@ action: "previewCamera" })); }); - + window.onblur = function() { // Fake a change event var ev = document.createEvent("HTMLEvents"); @@ -1476,6 +1501,29 @@ +
Grabbable:
+
+
+ grabbable + + + +
+ +
+ triggerable + + + +
+ +
+ ignore inverse-kinematics + + + +
+
From be51040420e363394bb1c3aa1cc5da8874a2ae54 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 12 Mar 2016 13:17:42 -0800 Subject: [PATCH 206/258] grabbable controlls are working --- examples/html/entityProperties.html | 73 ++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 92df997ac2..cdba00d245 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -243,18 +243,26 @@ } - function createUserDataChanger(groupName, keyName, propertyElement, userData) { - return function() { - var properties = {}; - // // this.checked - // properties['userData'] = ... JSON.stringify (...) - // EventBridge.emitWebEvent( - // JSON.stringify({ - // type: "update", - // properties: properties, - // }) - // ); + function userDataChanger(groupName, keyName, checkBoxElement, userDataElement) { + var properties = {}; + var parsedData = {}; + try { + parsedData = JSON.parse(userDataElement.value); + } catch(e) {} + + if (!(groupName in parsedData)) { + parsedData[groupName] = {} } + parsedData[groupName][keyName] = checkBoxElement.checked; + properties['userData'] = JSON.stringify(parsedData); + userDataElement.value = properties['userData']; + + EventBridge.emitWebEvent( + JSON.stringify({ + type: "update", + properties: properties, + }) + ); }; @@ -321,9 +329,9 @@ var elCollideOtherAvatar = document.getElementById("property-collide-otherAvatar"); var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); - var elGrabbable = document.getElementById("property-grabbable" ); - var elWantsTrigger = document.getElementById("property-wants-trigger" ); - var elIgnoreIK = document.getElementById("property-ignore-ik" ); + var elGrabbable = document.getElementById("property-grabbable"); + var elWantsTrigger = document.getElementById("property-wants-trigger"); + var elIgnoreIK = document.getElementById("property-ignore-ik"); var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); @@ -544,9 +552,25 @@ elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; - elGrabbable.checked = properties.collidesWith.indexOf("grabbable") > -1; - elWantsTrigger.checked = properties.collidesWith.indexOf("wantsTrigger") > -1; - elIgnoreIK.checked = properties.collidesWith.indexOf("ignoreIK") > -1; + elGrabbable.checked = false; + elWantsTrigger.checked = false; + elIgnoreIK.checked = false; + var parsedUserData = {} + try { + debugPrint("OKOKOK:" + properties.userData); + parsedUserData = JSON.parse(properties.userData); + } catch(e) {} + if ("grabbableKey" in parsedUserData) { + if (parsedUserData["grabbableKey"].grabbable) { + elGrabbable.checked = true; + } + if (parsedUserData["grabbableKey"].wantsTrigger) { + elWantsTrigger.checked = true; + } + if (parsedUserData["grabbableKey"].ignoreIK) { + elIgnoreIK.checked = true; + } + } elCollisionSoundURL.value = properties.collisionSoundURL; elLifetime.value = properties.lifetime; @@ -777,12 +801,15 @@ updateCheckedSubProperty("collidesWith", properties.collidesWith, elCollideOtherAvatar, 'otherAvatar'); }); - elGrabbable.addEventListener('change', createUserDataChanger("grabbableKey", "grabbable", - elGrabbable, properties.userData)); - elWantsTrigger.addEventListener('change', createUserDataChanger("grabbableKey", "wantsTrigger", - elWantsTrigger, properties.userData)); - elIgnoreIK.addEventListener('change', createUserDataChanger("grabbableKey", "ignoreIK", - elIgnoreIK, properties.userData)); + elGrabbable.addEventListener('change', function() { + userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData); + }); + elWantsTrigger.addEventListener('change', function() { + userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData); + }); + elIgnoreIK.addEventListener('change', function() { + userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData); + }); elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); From cca4a93b2b604b036588e32135d8062f251e5057 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 12 Mar 2016 14:09:52 -0800 Subject: [PATCH 207/258] don't full up userData with default grabbable data --- examples/html/entityProperties.html | 46 ++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index cdba00d245..ae42ea7caf 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -243,7 +243,13 @@ } - function userDataChanger(groupName, keyName, checkBoxElement, userDataElement) { + function isGrabbableByDefault(properties) { + return properties.type == "Box" || + properties.type == "Sphere" || + properties.dynamic + } + + function userDataChanger(groupName, keyName, checkBoxElement, userDataElement, defaultValue) { var properties = {}; var parsedData = {}; try { @@ -253,8 +259,20 @@ if (!(groupName in parsedData)) { parsedData[groupName] = {} } - parsedData[groupName][keyName] = checkBoxElement.checked; - properties['userData'] = JSON.stringify(parsedData); + delete parsedData[groupName][keyName]; + if (checkBoxElement.checked !== defaultValue) { + parsedData[groupName][keyName] = checkBoxElement.checked; + } + + if (Object.keys(parsedData[groupName]).length == 0) { + delete parsedData[groupName]; + } + if (Object.keys(parsedData).length > 0) { + properties['userData'] = JSON.stringify(parsedData); + } else { + properties['userData'] = ''; + } + userDataElement.value = properties['userData']; EventBridge.emitWebEvent( @@ -552,23 +570,23 @@ elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; - elGrabbable.checked = false; + // boxes and sphere are grabbable by default + elGrabbable.checked = isGrabbableByDefault(properties); elWantsTrigger.checked = false; elIgnoreIK.checked = false; var parsedUserData = {} try { - debugPrint("OKOKOK:" + properties.userData); parsedUserData = JSON.parse(properties.userData); } catch(e) {} if ("grabbableKey" in parsedUserData) { - if (parsedUserData["grabbableKey"].grabbable) { - elGrabbable.checked = true; + if ("grabbable" in parsedUserData["grabbableKey"]) { + elGrabbable.checked = parsedUserData["grabbableKey"].grabbable; } - if (parsedUserData["grabbableKey"].wantsTrigger) { - elWantsTrigger.checked = true; + if ("wantsTrigger" in parsedUserData["grabbableKey"]) { + elWantsTrigger.checked = parsedUserData["grabbableKey"].wantsTrigger; } - if (parsedUserData["grabbableKey"].ignoreIK) { - elIgnoreIK.checked = true; + if ("ignoreIK" in parsedUserData["grabbableKey"]) { + elIgnoreIK.checked = parsedUserData["grabbableKey"].ignoreIK; } } @@ -802,13 +820,13 @@ }); elGrabbable.addEventListener('change', function() { - userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData); + userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, isGrabbableByDefault(properties)); }); elWantsTrigger.addEventListener('change', function() { - userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData); + userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); }); elIgnoreIK.addEventListener('change', function() { - userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData); + userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData, false); }); elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); From ea95295e662d36f3c63f3cf67134354b4c5d40cf Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sat, 12 Mar 2016 14:52:26 -0800 Subject: [PATCH 208/258] ApplicationOveraly: Fix for gray line at top of HMD UI overlay --- interface/src/ui/ApplicationOverlay.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 14a3475610..54b56ea4f8 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -284,7 +284,8 @@ void ApplicationOverlay::buildFramebufferObject() { // If the overlay framebuffer still has no color attachment, no textures were available for rendering, so build a new one if (!_overlayFramebuffer->getRenderBuffer(0)) { - auto colorBuffer = gpu::TexturePointer(gpu::Texture::create2D(COLOR_FORMAT, width, height, DEFAULT_SAMPLER)); + const gpu::Sampler OVERLAY_SAMPLER(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP); + auto colorBuffer = gpu::TexturePointer(gpu::Texture::create2D(COLOR_FORMAT, width, height, OVERLAY_SAMPLER)); _overlayFramebuffer->setRenderBuffer(0, colorBuffer); } } From 96bc17cd5ee84dda5f2a9c7280b2c8befcada4cd Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Mar 2016 16:01:10 -0800 Subject: [PATCH 209/258] Update photo_sphere.js --- examples/data_visualization/photo_sphere.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/data_visualization/photo_sphere.js b/examples/data_visualization/photo_sphere.js index d8be423bd7..c62fb7d122 100644 --- a/examples/data_visualization/photo_sphere.js +++ b/examples/data_visualization/photo_sphere.js @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var photoSphere, light;; +var photoSphere, light; //equirectangular var url = 'http://hifi-content.s3.amazonaws.com/james/projection_objects/IMG_9167.JPG'; @@ -57,4 +57,4 @@ function cleanup() { Script.scriptEnding.connect(cleanup); createPhotoSphere(); -createLight(); \ No newline at end of file +createLight(); From d868b541c4f9cfe9b49b9e253be81a09d3f3f3e3 Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Sat, 12 Mar 2016 17:19:29 -0800 Subject: [PATCH 210/258] Separate the request limit value from the active request value Use _requestLimit as the download limit, and track active downloads using _requestsActive. If the limit is changes below the active count, it will continue downloading all active requests, but not allow new requests until the active count gets below the limit. If the limit increases, the pending request queue will be checked immediately to fill the available download slots. --- libraries/networking/src/ResourceCache.cpp | 42 ++++++++++++++-------- libraries/networking/src/ResourceCache.h | 10 ++++-- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index dabf1b098b..249f22054d 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -56,6 +56,15 @@ void ResourceCache::refresh(const QUrl& url) { } } +void ResourceCache::setRequestLimit(int limit) { + _requestLimit = limit; + + // Now go fill any new request spots + while (attemptHighestPriorityRequest()) { + // just keep looping until we reach the new limit or no more pending requests + } +} + void ResourceCache::getResourceAsynchronously(const QUrl& url) { qCDebug(networking) << "ResourceCache::getResourceAsynchronously" << url.toString(); _resourcesToBeGottenLock.lockForWrite(); @@ -150,31 +159,37 @@ void ResourceCache::clearUnusedResource() { } } -void ResourceCache::attemptRequest(Resource* resource) { +bool ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); // Disable request limiting for ATP if (resource->getURL().scheme() != URL_SCHEME_ATP) { - if (_requestLimit <= 0) { + if (_requestsActive >= _requestLimit) { // wait until a slot becomes available sharedItems->_pendingRequests.append(resource); - return; + return false; } - --_requestLimit; - } + ++_requestsActive; + } sharedItems->_loadingRequests.append(resource); resource->makeRequest(); + return true; } void ResourceCache::requestCompleted(Resource* resource) { - auto sharedItems = DependencyManager::get(); - sharedItems->_loadingRequests.removeOne(resource); - if (resource->getURL().scheme() != URL_SCHEME_ATP) { - ++_requestLimit; - } - + auto sharedItems = DependencyManager::get(); + sharedItems->_loadingRequests.removeOne(resource); + if (resource->getURL().scheme() != URL_SCHEME_ATP) { + --_requestsActive; + } + + attemptHighestPriorityRequest(); +} + +bool ResourceCache::attemptHighestPriorityRequest() { + auto sharedItems = DependencyManager::get(); // look for the highest priority pending request int highestIndex = -1; float highestPriority = -FLT_MAX; @@ -191,13 +206,12 @@ void ResourceCache::requestCompleted(Resource* resource) { } i++; } - if (highestIndex >= 0) { - attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex)); - } + return (highestIndex >= 0) && attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex)); } const int DEFAULT_REQUEST_LIMIT = 10; int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT; +int ResourceCache::_requestsActive = 0; Resource::Resource(const QUrl& url, bool delayLoad) : _url(url), diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 6fbf54c49d..e08d223ad7 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -67,8 +67,10 @@ class ResourceCache : public QObject { Q_OBJECT public: - static void setRequestLimit(int limit) { _requestLimit = limit; } + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } + + static int getRequestsActive() { return _requestsActive; } void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize); qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; } @@ -105,8 +107,11 @@ protected: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); - Q_INVOKABLE static void attemptRequest(Resource* resource); + /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading + /// \return true if the resource began loading, otherwise false if the resource is in the pending queue + Q_INVOKABLE static bool attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); + static bool attemptHighestPriorityRequest(); private: friend class Resource; @@ -115,6 +120,7 @@ private: int _lastLRUKey = 0; static int _requestLimit; + static int _requestsActive; void getResourceAsynchronously(const QUrl& url); QReadWriteLock _resourcesToBeGottenLock; From 00829db3755247e7505ccd2d1fb17dd6ffe18584 Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Sat, 12 Mar 2016 17:27:43 -0800 Subject: [PATCH 211/258] Fill in the downloads line of the stats window Will show the active download, current download limit and how many pending requests --- interface/resources/qml/Stats.qml | 3 ++- interface/src/ui/Stats.cpp | 1 + interface/src/ui/Stats.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index e50f43674e..f6d4f4bdae 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -166,7 +166,8 @@ Item { color: root.fontColor; font.pixelSize: root.fontSize visible: root.expanded; - text: "Downloads: "; + text: "Downloads: " + root.downloads + "/" + root.downloadLimit + + ", Q: " + root.downloadsPending; } } } diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index ac47c55eca..4684862584 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -193,6 +193,7 @@ void Stats::updateStats(bool force) { } STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size()); + STAT_UPDATE(downloadLimit, ResourceCache::getRequestLimit()) STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount()); // TODO fix to match original behavior //stringstream downloads; diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index ebcb80c404..09b9c78637 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -56,6 +56,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, audioMixerKbps, 0) STATS_PROPERTY(int, audioMixerPps, 0) STATS_PROPERTY(int, downloads, 0) + STATS_PROPERTY(int, downloadLimit, 0) STATS_PROPERTY(int, downloadsPending, 0) STATS_PROPERTY(int, triangles, 0) STATS_PROPERTY(int, quads, 0) @@ -135,6 +136,7 @@ signals: void audioMixerKbpsChanged(); void audioMixerPpsChanged(); void downloadsChanged(); + void downloadLimitChanged(); void downloadsPendingChanged(); void trianglesChanged(); void quadsChanged(); From b7a47d7bf272be4937df9490308e3f6d3b661bad Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Sat, 12 Mar 2016 17:35:57 -0800 Subject: [PATCH 212/258] Tabs -> Spaces --- interface/src/ui/Stats.cpp | 2 +- interface/src/ui/Stats.h | 4 ++-- libraries/networking/src/ResourceCache.cpp | 26 +++++++++++----------- libraries/networking/src/ResourceCache.h | 12 +++++----- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 4684862584..23d2b87194 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -193,7 +193,7 @@ void Stats::updateStats(bool force) { } STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size()); - STAT_UPDATE(downloadLimit, ResourceCache::getRequestLimit()) + STAT_UPDATE(downloadLimit, ResourceCache::getRequestLimit()) STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount()); // TODO fix to match original behavior //stringstream downloads; diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 09b9c78637..c6bc13b52c 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -56,7 +56,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, audioMixerKbps, 0) STATS_PROPERTY(int, audioMixerPps, 0) STATS_PROPERTY(int, downloads, 0) - STATS_PROPERTY(int, downloadLimit, 0) + STATS_PROPERTY(int, downloadLimit, 0) STATS_PROPERTY(int, downloadsPending, 0) STATS_PROPERTY(int, triangles, 0) STATS_PROPERTY(int, quads, 0) @@ -136,7 +136,7 @@ signals: void audioMixerKbpsChanged(); void audioMixerPpsChanged(); void downloadsChanged(); - void downloadLimitChanged(); + void downloadLimitChanged(); void downloadsPendingChanged(); void trianglesChanged(); void quadsChanged(); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 249f22054d..e345bed81c 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -57,12 +57,12 @@ void ResourceCache::refresh(const QUrl& url) { } void ResourceCache::setRequestLimit(int limit) { - _requestLimit = limit; + _requestLimit = limit; - // Now go fill any new request spots - while (attemptHighestPriorityRequest()) { - // just keep looping until we reach the new limit or no more pending requests - } + // Now go fill any new request spots + while (attemptHighestPriorityRequest()) { + // just keep looping until we reach the new limit or no more pending requests + } } void ResourceCache::getResourceAsynchronously(const QUrl& url) { @@ -175,21 +175,21 @@ bool ResourceCache::attemptRequest(Resource* resource) { sharedItems->_loadingRequests.append(resource); resource->makeRequest(); - return true; + return true; } void ResourceCache::requestCompleted(Resource* resource) { - auto sharedItems = DependencyManager::get(); - sharedItems->_loadingRequests.removeOne(resource); - if (resource->getURL().scheme() != URL_SCHEME_ATP) { - --_requestsActive; - } + auto sharedItems = DependencyManager::get(); + sharedItems->_loadingRequests.removeOne(resource); + if (resource->getURL().scheme() != URL_SCHEME_ATP) { + --_requestsActive; + } - attemptHighestPriorityRequest(); + attemptHighestPriorityRequest(); } bool ResourceCache::attemptHighestPriorityRequest() { - auto sharedItems = DependencyManager::get(); + auto sharedItems = DependencyManager::get(); // look for the highest priority pending request int highestIndex = -1; float highestPriority = -FLT_MAX; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index e08d223ad7..a8ab51b7f7 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -67,10 +67,10 @@ class ResourceCache : public QObject { Q_OBJECT public: - static void setRequestLimit(int limit); + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } - static int getRequestsActive() { return _requestsActive; } + static int getRequestsActive() { return _requestsActive; } void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize); qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; } @@ -107,11 +107,11 @@ protected: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); - /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading - /// \return true if the resource began loading, otherwise false if the resource is in the pending queue + /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading + /// \return true if the resource began loading, otherwise false if the resource is in the pending queue Q_INVOKABLE static bool attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); - static bool attemptHighestPriorityRequest(); + static bool attemptHighestPriorityRequest(); private: friend class Resource; @@ -120,7 +120,7 @@ private: int _lastLRUKey = 0; static int _requestLimit; - static int _requestsActive; + static int _requestsActive; void getResourceAsynchronously(const QUrl& url); QReadWriteLock _resourcesToBeGottenLock; From b921ac77574c58dcc89f58cebdeac7ad5b8e4d03 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 11:32:48 -0700 Subject: [PATCH 213/258] MyAvatar: prevent roll and pitch in avatar via snapshot url. --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9302c3b47d..1754b0b8ff 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1787,7 +1787,7 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition, << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w; // orient the user to face the target - glm::quat quatOrientation = newOrientation; + glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation); if (shouldFaceLocation) { quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); From 02b2281defcf2e42d2f2018dcd6aee434e562294 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 16:51:57 -0700 Subject: [PATCH 214/258] AnimVarient.h: cppcheck fixes * make all constructors explicit. * remove static string comparison in assert. --- libraries/animation/src/AnimVariant.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index 531e2c4a2d..3466013ff6 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -37,12 +37,12 @@ public: static const AnimVariant False; AnimVariant() : _type(Type::Bool) { memset(&_val, 0, sizeof(_val)); } - AnimVariant(bool value) : _type(Type::Bool) { _val.boolVal = value; } - AnimVariant(int value) : _type(Type::Int) { _val.intVal = value; } - AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; } - AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast(&_val) = value; } - AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast(&_val) = value; } - AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; } + explicit AnimVariant(bool value) : _type(Type::Bool) { _val.boolVal = value; } + explicit AnimVariant(int value) : _type(Type::Int) { _val.intVal = value; } + explicit AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; } + explicit AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast(&_val) = value; } + explicit AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast(&_val) = value; } + explicit AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; } bool isBool() const { return _type == Type::Bool; } bool isInt() const { return _type == Type::Int; } @@ -250,7 +250,7 @@ public: qCDebug(animation) << " " << pair.first << "=" << pair.second.getString(); break; default: - assert("AnimVariant::Type" == "valid"); + assert(("invalid AnimVariant::Type", false)); } } } From 11fcf00b2adb29f2fd679542130cf1a6b22c22b9 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 16:55:34 -0700 Subject: [PATCH 215/258] AnimSkeleton.h: made single argument ctors explicit --- libraries/animation/src/AnimSkeleton.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index fc246bc4c0..e2cd20d63e 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -23,8 +23,8 @@ public: using Pointer = std::shared_ptr; using ConstPointer = std::shared_ptr; - AnimSkeleton(const FBXGeometry& fbxGeometry); - AnimSkeleton(const std::vector& joints); + explicit AnimSkeleton(const FBXGeometry& fbxGeometry); + explicit AnimSkeleton(const std::vector& joints); int nameToJointIndex(const QString& jointName) const; const QString& getJointName(int jointIndex) const; int getNumJoints() const; From 9f305560841f5ccf77ad293edbef8350d4b82cc2 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 17:17:34 -0700 Subject: [PATCH 216/258] libraries/animation: cppcheck fixes * Fix for potential bug in AnimLoop due to _maxFrameIndexHint being uninitialized. * made more single argument constructors explicit. --- libraries/animation/src/AnimExpression.h | 8 ++++---- libraries/animation/src/AnimInverseKinematics.h | 2 +- libraries/animation/src/AnimNodeLoader.h | 2 +- libraries/animation/src/AnimStateMachine.h | 2 +- libraries/animation/src/AnimationCache.h | 4 ++-- libraries/animation/src/AnimationLoop.cpp | 2 ++ libraries/animation/src/AnimationLoop.h | 2 +- libraries/animation/src/Rig.cpp | 12 +----------- libraries/animation/src/Rig.h | 1 + 9 files changed, 14 insertions(+), 21 deletions(-) diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 468217f5b3..87fb3ca20c 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -21,7 +21,7 @@ class AnimExpression { public: friend class AnimTests; - AnimExpression(const QString& str); + explicit AnimExpression(const QString& str); protected: struct Token { enum Type { @@ -49,8 +49,8 @@ protected: Comma, Error }; - Token(Type type) : type {type} {} - Token(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} + explicit Token(Type type) : type {type} {} + explicit Token(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} explicit Token(int val) : type {Type::Int}, intVal {val} {} explicit Token(bool val) : type {Type::Bool}, intVal {val} {} explicit Token(float val) : type {Type::Float}, floatVal {val} {} @@ -82,7 +82,7 @@ protected: Modulus, UnaryMinus }; - OpCode(Type type) : type {type} {} + explicit OpCode(Type type) : type {type} {} explicit OpCode(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} explicit OpCode(const QString& str) : type {Type::Identifier}, strVal {str} {} explicit OpCode(int val) : type {Type::Int}, intVal {val} {} diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index aeb718668a..182e7b3492 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -25,7 +25,7 @@ class RotationConstraint; class AnimInverseKinematics : public AnimNode { public: - AnimInverseKinematics(const QString& id); + explicit AnimInverseKinematics(const QString& id); virtual ~AnimInverseKinematics() override; void loadDefaultPoses(const AnimPoseVec& poses); diff --git a/libraries/animation/src/AnimNodeLoader.h b/libraries/animation/src/AnimNodeLoader.h index bc7d574c39..27b94f81bb 100644 --- a/libraries/animation/src/AnimNodeLoader.h +++ b/libraries/animation/src/AnimNodeLoader.h @@ -25,7 +25,7 @@ class AnimNodeLoader : public QObject { Q_OBJECT public: - AnimNodeLoader(const QUrl& url); + explicit AnimNodeLoader(const QUrl& url); signals: void success(AnimNode::Pointer node); diff --git a/libraries/animation/src/AnimStateMachine.h b/libraries/animation/src/AnimStateMachine.h index 6a28ef1825..d92b94d1b5 100644 --- a/libraries/animation/src/AnimStateMachine.h +++ b/libraries/animation/src/AnimStateMachine.h @@ -110,7 +110,7 @@ protected: public: - AnimStateMachine(const QString& id); + explicit AnimStateMachine(const QString& id); virtual ~AnimStateMachine() override; virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) override; diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index 6143d9b42e..e6a795c864 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -38,7 +38,7 @@ protected: virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, const void* extra); private: - AnimationCache(QObject* parent = NULL); + explicit AnimationCache(QObject* parent = NULL); virtual ~AnimationCache() { } }; @@ -51,7 +51,7 @@ class Animation : public Resource { public: - Animation(const QUrl& url); + explicit Animation(const QUrl& url); const FBXGeometry& getGeometry() const { return *_geometry; } diff --git a/libraries/animation/src/AnimationLoop.cpp b/libraries/animation/src/AnimationLoop.cpp index f6a2877966..3d7bca863f 100644 --- a/libraries/animation/src/AnimationLoop.cpp +++ b/libraries/animation/src/AnimationLoop.cpp @@ -40,6 +40,7 @@ AnimationLoop::AnimationLoop(const AnimationDetails& animationDetails) : _lastFrame(animationDetails.lastFrame), _running(animationDetails.running), _currentFrame(animationDetails.currentFrame), + _maxFrameIndexHint(MAXIMUM_POSSIBLE_FRAME), _resetOnRunning(true), _lastSimulated(usecTimestampNow()) { @@ -55,6 +56,7 @@ AnimationLoop::AnimationLoop(float fps, bool loop, bool hold, bool startAutomati _lastFrame(lastFrame), _running(running), _currentFrame(currentFrame), + _maxFrameIndexHint(MAXIMUM_POSSIBLE_FRAME), _resetOnRunning(true), _lastSimulated(usecTimestampNow()) { diff --git a/libraries/animation/src/AnimationLoop.h b/libraries/animation/src/AnimationLoop.h index 10664c47e7..6adfbf35e2 100644 --- a/libraries/animation/src/AnimationLoop.h +++ b/libraries/animation/src/AnimationLoop.h @@ -19,7 +19,7 @@ public: static const float MAXIMUM_POSSIBLE_FRAME; AnimationLoop(); - AnimationLoop(const AnimationDetails& animationDetails); + explicit AnimationLoop(const AnimationDetails& animationDetails); AnimationLoop(float fps, bool loop, bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index bca90b242a..ae9adc71c2 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -37,17 +37,7 @@ static bool isEqual(const glm::quat& p, const glm::quat& q) { return 1.0f - fabsf(glm::dot(p, q)) <= EPSILON; } -#ifdef NDEBUG -#define ASSERT(cond) -#else -#define ASSERT(cond) \ - do { \ - if (!(cond)) { \ - int* ptr = nullptr; \ - *ptr = 10; \ - } \ - } while (0) -#endif +#define ASSERT(cond) assert(cond) // 2 meter tall dude const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 0.9f, 0.0f); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 50313d10e7..1f9a02d8ab 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -83,6 +83,7 @@ public: Hover }; + Rig() {} virtual ~Rig() {} void destroyAnimGraph(); From 54cc49283cb831214c9f620b896f32d91d77c933 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 18:19:42 -0700 Subject: [PATCH 217/258] libraries/avatars: cppcheck warning fixes --- libraries/avatars/src/AvatarData.cpp | 4 ++-- libraries/avatars/src/HeadData.cpp | 2 ++ libraries/avatars/src/HeadData.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 067ab0603b..adb942417d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1115,7 +1115,7 @@ void AvatarData::detachOne(const QString& modelURL, const QString& jointName) { return; } QVector attachmentData = getAttachmentData(); - for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); it++) { + for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); ++it) { if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { attachmentData.erase(it); setAttachmentData(attachmentData); @@ -1134,7 +1134,7 @@ void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { it = attachmentData.erase(it); } else { - it++; + ++it; } } setAttachmentData(attachmentData); diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index 1d664aa3ff..b98112d6e0 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -42,6 +42,8 @@ HeadData::HeadData(AvatarData* owningAvatar) : _rightEyeBlink(0.0f), _averageLoudness(0.0f), _browAudioLift(0.0f), + _audioAverageLoudness(0.0f), + _pupilDilation(0.0f), _owningAvatar(owningAvatar) { diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index dac266f4a2..fef77c6f8f 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -32,7 +32,7 @@ class QJsonObject; class HeadData { public: - HeadData(AvatarData* owningAvatar); + explicit HeadData(AvatarData* owningAvatar); virtual ~HeadData() { }; // degrees From 1e94d9bdf58f04e65cc299fef0fdf37f2117b757 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 18:56:15 -0700 Subject: [PATCH 218/258] interface/src/avatar: cppcheck fixes --- examples/utilities/tools/developerMenuItems.js | 6 +++--- interface/src/avatar/Avatar.cpp | 3 +-- interface/src/avatar/Avatar.h | 2 +- interface/src/avatar/AvatarActionHold.cpp | 1 - interface/src/avatar/AvatarManager.cpp | 4 ++-- interface/src/avatar/AvatarManager.h | 4 ++-- interface/src/avatar/AvatarUpdate.cpp | 2 +- interface/src/avatar/Head.h | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +++--- interface/src/avatar/MyAvatar.h | 8 ++++---- interface/src/avatar/MyCharacterController.cpp | 11 ++++++----- interface/src/avatar/MyCharacterController.h | 2 +- 12 files changed, 25 insertions(+), 26 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index 2e6c5a1141..549bed0bc4 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -36,11 +36,11 @@ var AUDIO_LISTENER_MODE_CUSTOM = "Audio from custom position"; // be sure that the audio listener options are in the right order (same as the enumerator) var AUDIO_LISTENER_OPTIONS = [ - // MyAvatar.FROM_HEAD (0) + // MyAvatar.audioListenerModeHead (0) AUDIO_LISTENER_MODE_FROM_HEAD, - // MyAvatar.FROM_CAMERA (1) + // MyAvatar.audioListenerModeCamera (1) AUDIO_LISTENER_MODE_FROM_CAMERA, - // MyAvatar.CUSTOM (2) + // MyAvatar.audioListenerCustom (2) AUDIO_LISTENER_MODE_CUSTOM ]; var AUDIO_STEREO_INPUT = "Stereo Input"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ca242a2ca2..2a94ed30e2 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -972,7 +972,6 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g glm::vec3 perpCos = glm::normalize(glm::cross(axis, perpSin)); perpSin = glm::cross(perpCos, axis); - float anglea = 0.0f; float angleb = 0.0f; QVector points; @@ -980,7 +979,7 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g // the rectangles that comprise the sides of the cone section are // referenced by "a" and "b" in one dimension, and "1", and "2" in the other dimension. - anglea = angleb; + int anglea = angleb; angleb = ((float)(i+1) / (float)NUM_BODY_CONE_SIDES) * TWO_PI; float sa = sinf(anglea); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 7020de377f..01548c9066 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -57,7 +57,7 @@ class Avatar : public AvatarData { Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: - Avatar(RigPointer rig = nullptr); + explicit Avatar(RigPointer rig = nullptr); ~Avatar(); typedef render::Payload Payload; diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 5087f7955d..629b3aac12 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -308,7 +308,6 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { hand = _hand; } - ok = true; auto myAvatar = DependencyManager::get()->getMyAvatar(); holderID = myAvatar->getSessionUUID(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 8e48237b8e..bcb54d6c52 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -63,11 +63,11 @@ void AvatarManager::registerMetaTypes(QScriptEngine* engine) { } AvatarManager::AvatarManager(QObject* parent) : - _avatarFades() + _avatarFades(), + _myAvatar(std::make_shared(std::make_shared())) { // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar qRegisterMetaType >("NodeWeakPointer"); - _myAvatar = std::make_shared(std::make_shared()); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::BulkAvatarData, this, "processAvatarDataPacket"); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 2aff98a1d2..57fc1022ea 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -71,8 +71,8 @@ public slots: void updateAvatarRenderStatus(bool shouldRenderAvatars); private: - AvatarManager(QObject* parent = 0); - AvatarManager(const AvatarManager& other); + explicit AvatarManager(QObject* parent = 0); + explicit AvatarManager(const AvatarManager& other); void simulateAvatarFades(float deltaTime); diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index 4881e3eaec..a52b584527 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -16,7 +16,7 @@ #include #include "InterfaceLogging.h" -AvatarUpdate::AvatarUpdate() : GenericThread(), _lastAvatarUpdate(0) { +AvatarUpdate::AvatarUpdate() : GenericThread(), _lastAvatarUpdate(0), _isHMDMode(false) { setObjectName("Avatar Update"); // GenericThread::initialize uses this to set the thread name. Settings settings; const int DEFAULT_TARGET_AVATAR_SIMRATE = 60; diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index ec88b295f7..614e286329 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -28,7 +28,7 @@ class Avatar; class Head : public HeadData { public: - Head(Avatar* owningAvatar); + explicit Head(Avatar* owningAvatar); void init(); void reset(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9302c3b47d..d0be9c0be0 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1522,9 +1522,9 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe // (1) braking --> short timescale (aggressive motor assertion) // (2) pushing --> medium timescale (mild motor assertion) // (3) inactive --> long timescale (gentle friction for low speeds) - float MIN_KEYBOARD_MOTOR_TIMESCALE = 0.125f; - float MAX_KEYBOARD_MOTOR_TIMESCALE = 0.4f; - float MIN_KEYBOARD_BRAKE_SPEED = 0.3f; + const float MIN_KEYBOARD_MOTOR_TIMESCALE = 0.125f; + const float MAX_KEYBOARD_MOTOR_TIMESCALE = 0.4f; + const float MIN_KEYBOARD_BRAKE_SPEED = 0.3f; float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE; bool isThrust = (glm::length2(_thrust) > EPSILON); if (_isPushing || isThrust || diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f834a627b2..37a2e752e6 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -63,9 +63,9 @@ class MyAvatar : public Avatar { Q_PROPERTY(AudioListenerMode audioListenerMode READ getAudioListenerMode WRITE setAudioListenerMode) Q_PROPERTY(glm::vec3 customListenPosition READ getCustomListenPosition WRITE setCustomListenPosition) Q_PROPERTY(glm::quat customListenOrientation READ getCustomListenOrientation WRITE setCustomListenOrientation) - Q_PROPERTY(AudioListenerMode FROM_HEAD READ getAudioListenerModeHead) - Q_PROPERTY(AudioListenerMode FROM_CAMERA READ getAudioListenerModeCamera) - Q_PROPERTY(AudioListenerMode CUSTOM READ getAudioListenerModeCustom) + Q_PROPERTY(AudioListenerMode audioListenerModeHead READ getAudioListenerModeHead) + Q_PROPERTY(AudioListenerMode audioListenerModeCamera READ getAudioListenerModeCamera) + Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom) //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) @@ -84,7 +84,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float energy READ getEnergy WRITE setEnergy) public: - MyAvatar(RigPointer rig); + explicit MyAvatar(RigPointer rig); ~MyAvatar(); virtual void simulateAttachments(float deltaTime) override; diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index ee77859337..6e52f4a949 100644 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -46,14 +46,15 @@ void MyCharacterController::updateShapeIfNecessary() { // NOTE: _shapeLocalOffset is already computed if (_radius > 0.0f) { - // HACK: use some simple mass property defaults for now - float mass = 100.0f; - btVector3 inertia(30.0f, 8.0f, 30.0f); - // create RigidBody if it doesn't exist if (!_rigidBody) { + + // HACK: use some simple mass property defaults for now + const float DEFAULT_AVATAR_MASS = 100.0f; + const btVector3 DEFAULT_AVATAR_INERTIA_TENSOR(30.0f, 8.0f, 30.0f); + btCollisionShape* shape = new btCapsuleShape(_radius, 2.0f * _halfHeight); - _rigidBody = new btRigidBody(mass, nullptr, shape, inertia); + _rigidBody = new btRigidBody(DEFAULT_AVATAR_MASS, nullptr, shape, DEFAULT_AVATAR_INERTIA_TENSOR); } else { btCollisionShape* shape = _rigidBody->getCollisionShape(); if (shape) { diff --git a/interface/src/avatar/MyCharacterController.h b/interface/src/avatar/MyCharacterController.h index 39f0f99917..265406bc6f 100644 --- a/interface/src/avatar/MyCharacterController.h +++ b/interface/src/avatar/MyCharacterController.h @@ -21,7 +21,7 @@ class MyAvatar; class MyCharacterController : public CharacterController { public: - MyCharacterController(MyAvatar* avatar); + explicit MyCharacterController(MyAvatar* avatar); ~MyCharacterController (); virtual void updateShapeIfNecessary() override; From 6c27bd9eb26042e9ca1443e5a3707218597a01cd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 13 Mar 2016 21:04:07 -0700 Subject: [PATCH 219/258] Update upload flow and make asset list dynamically sized --- interface/resources/qml/AssetServer.qml | 230 ++++++++++-------- .../AssetMappingsScriptingInterface.cpp | 19 +- .../AssetMappingsScriptingInterface.h | 2 +- 3 files changed, 139 insertions(+), 112 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c5ebb04819..3ed562f59a 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -36,7 +36,6 @@ Window { property var assetProxyModel: Assets.proxyModel; property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; - property alias currentFileUrl: fileUrlTextField.text; Settings { category: "Overlay.AssetServer" @@ -46,8 +45,8 @@ Window { } Component.onCompleted: { - assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError) - reload() + assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); + reload(); } function doDeleteFile(path) { @@ -220,47 +219,69 @@ Window { }); } - function chooseClicked() { - var browser = desktop.fileDialog({ - selectDirectory: false, - dir: currentDirectory - }); - browser.selectedFile.connect(function(url){ - fileUrlTextField.text = fileDialogHelper.urlToPath(url); - currentDirectory = browser.dir; - }); - } property var uploadOpen: false; + Timer { + id: timer + } function uploadClicked() { if (uploadOpen) { return; } uploadOpen = true; - var fileUrl = fileUrlTextField.text - var shouldAddToWorld = addToWorldCheckBox.checked + var fileUrl = ""; - var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); - var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; - var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); - - Assets.uploadFile(fileUrl, directory + filename, function(err, path) { - if (err) { - console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); - var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); - box.selected.connect(reload); - } else { - console.log("Asset Browser - finished uploading: ", fileUrl); - - if (shouldAddToWorld) { - addToWorld("atp:" + path); - } - - reload(); - } + var browser = desktop.fileDialog({ + selectDirectory: false, + dir: currentDirectory + }); + browser.canceled.connect(function() { + uploadOpen = false; + }); + browser.selectedFile.connect(function(url){ + var fileUrl = fileDialogHelper.urlToPath(url); + currentDirectory = browser.dir; + + //var fileUrl = fileUrlTextField.text + + var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); + var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; + var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); + + Assets.uploadFile(fileUrl, directory + filename, + function() { + // Upload started + uploadSpinner.visible = true; + uploadButton.enabled = false; + uploadProgressLabel.text = "In progress..."; + }, + function(err, path) { + print(err, path); + if (!err) { + uploadProgressLabel.text = "Upload Complete"; + timer.interval = 1000; + timer.repeat = false; + timer.triggered.connect(function() { + uploadSpinner.visible = false; + uploadButton.enabled = true; + uploadOpen = false; + }); + timer.start(); + console.log("Asset Browser - finished uploading: ", fileUrl); + reload(); + } else { + if (err > 0) { + console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); + var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); + } + uploadSpinner.visible = false; + uploadButton.enabled = true; + uploadOpen = false; + } + }) }); - uploadOpen = false; } function errorMessageBox(message) { @@ -272,8 +293,9 @@ Window { }); } - Column { + Item { width: pane.contentWidth + height: pane.height HifiControls.ContentSection { id: assetDirectory @@ -359,99 +381,95 @@ Window { } } } + } - HifiControls.Tree { - id: treeView - height: 400 - treeModel: assetProxyModel - colorScheme: root.colorScheme - anchors.left: parent.left - anchors.right: parent.right - MouseArea { - propagateComposedEvents: true - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: { - var index = treeView.indexAt(mouse.x, mouse.y); - contextMenu.currentIndex = index; - contextMenu.popup(); - } + HifiControls.Tree { + id: treeView + anchors.top: assetDirectory.bottom + anchors.bottom: uploadSection.top + anchors.margins: 12 + anchors.bottomMargin: 0 + treeModel: assetProxyModel + colorScheme: root.colorScheme + anchors.left: parent.left + anchors.right: parent.right + MouseArea { + propagateComposedEvents: true + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + print("onClicked"); + var index = treeView.indexAt(mouse.x, mouse.y); + print("onClicked", assetProxyModel.data(index, 0x0100)); + treeView.selection.select(index, 0x0001 | 0x0002 | 0x0010 | 0x0020); + print("done"); + //contextMenu.currentIndex = index; + //treeView.selection.clearSelection() + //treeView.selection.clear(); + //contextMenu.popup(); } } } - HifiControls.ContentSection { id: uploadSection - name: "" + name: "Upload A File" spacing: hifi.dimensions.contentSpacing.y - - HifiControls.TextField { - id: fileUrlTextField - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x - - label: "Upload File" - placeholderText: "Paste URL or choose file" - colorScheme: root.colorScheme - } + anchors.bottom: parent.bottom + height: 130 Item { - // Take the chooseButton out of the column flow. - id: chooseButtonContainer - anchors.top: fileUrlTextField.top - anchors.right: parent.right - - HifiControls.Button { - id: chooseButton - anchors.right: parent.right - - text: "Choose" - color: hifi.buttons.white - colorScheme: root.colorScheme - enabled: true - - width: 100 - - onClicked: root.chooseClicked() - } - } - - HifiControls.CheckBox { - id: addToWorldCheckBox - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x - - text: "Add to world on upload" - - opacity: canAddToWorld(fileUrlTextField.text) ? 1 : 0 - - checked: false - } - - Item { - // Take the uploadButton out of the column flow. - id: uploadButtonContainer - anchors.top: addToWorldCheckBox.top - anchors.right: parent.right - + height: parent.height + width: parent.width HifiControls.Button { id: uploadButton anchors.right: parent.right - text: "Upload" + text: "Choose File" color: hifi.buttons.blue colorScheme: root.colorScheme height: 30 width: 155 - enabled: fileUrlTextField.text != "" onClicked: root.uploadClicked() } + + Item { + id: uploadSpinner + visible: false + anchors.top: parent.top + anchors.left: parent.left + width: 40 + height: 32 + + Image { + id: image + width: 24 + height: 24 + source: "../images/Loading-Outer-Ring.png" + RotationAnimation on rotation { + loops: Animation.Infinite + from: 0 + to: 360 + duration: 2000 + } + } + Image { + width: 24 + height: 24 + source: "../images/Loading-Inner-H.png" + } + HifiControls.Label { + id: uploadProgressLabel + anchors.left: image.right + anchors.leftMargin: 10 + anchors.verticalCenter: image.verticalCenter + text: "In progress..." + colorScheme: root.colorScheme + } + + } } - HifiControls.VerticalSpacer {} } } } diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 32b697459c..0a2a12ee24 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -80,11 +80,16 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback request->start(); } -void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { +void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback) { + static const QString helpText = + "Upload your asset to a specific folder by enter the full path. Specifying " + "a new folder name will automatically create that folder for you."; + auto offscreenUi = DependencyManager::get(); - auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); + auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", helpText, mapping); if (!result.isValid()) { + completedCallback.call({ -1 }); return; } mapping = result.toString(); @@ -100,19 +105,22 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (button == QMessageBox::No) { + completedCallback.call({ -1 }); return; } } + startedCallback.call(); + auto upload = DependencyManager::get()->createUpload(path); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { - if (callback.isCallable()) { + if (completedCallback.isCallable()) { QJSValueList args { uint8_t(upload->getError()) }; - callback.call(args); + completedCallback.call(args); } } else { - setMapping(mapping, hash, callback); + setMapping(mapping, hash, completedCallback); } upload->deleteLater(); @@ -198,6 +206,7 @@ AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, } + static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); void AssetMappingModel::refresh() { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 35a1c1ae7e..5465901ed4 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -64,7 +64,7 @@ public: Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); - Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); + Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue()); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); From 960047f4127ac15fbbec04f2febd790474c65d93 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 13 Mar 2016 21:06:52 -0700 Subject: [PATCH 220/258] Remove right click selection --- interface/resources/qml/AssetServer.qml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3ed562f59a..b6d86b17fd 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -398,15 +398,9 @@ Window { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - print("onClicked"); var index = treeView.indexAt(mouse.x, mouse.y); - print("onClicked", assetProxyModel.data(index, 0x0100)); - treeView.selection.select(index, 0x0001 | 0x0002 | 0x0010 | 0x0020); - print("done"); - //contextMenu.currentIndex = index; - //treeView.selection.clearSelection() - //treeView.selection.clear(); - //contextMenu.popup(); + contextMenu.currentIndex = index; + contextMenu.popup(); } } } From a7f21d5fceab614f2f5c236d0cf47c0dd03859af Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 14 Mar 2016 10:36:19 -0700 Subject: [PATCH 221/258] Clena up comments, ready to PR --- libraries/gpu/src/gpu/Context.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 013433102a..46c07e4265 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -76,7 +76,10 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const { _projectionInverse = glm::inverse(_projection); - // _viewInverse = glm::inverse(_view); + + // Get the viewEyeToWorld matrix form the transformView as passed to the gpu::Batch + // this is the "_viewInverse" fed to the shader + // Genetrate the "_view" matrix as wekll forom the xform xformView.getMatrix(_viewInverse); _view = glm::inverse(_viewInverse); @@ -90,12 +93,9 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S TransformCamera result = *this; Transform offsetTransform = xformView; if (!_stereo._skybox) { - result._view = _stereo._eyeViews[eye] * result._view; offsetTransform.postTranslate(-Vec3(_stereo._eyeViews[eye][3])); } else { - // glm::mat4 skyboxView = _stereo._eyeViews[eye]; - // skyboxView[3] = vec4(0, 0, 0, 1); - // result._view = skyboxView * result._view; + // FIXME: If "skybox" the ipd is set to 0 for now, let s try to propose a better solution for this in the future } result._projection = _stereo._eyeProjections[eye]; result.recomputeDerived(xformView); From 5292e537ea5f5fb21f4669f681e697989c8b391d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Mar 2016 11:22:01 -0700 Subject: [PATCH 222/258] further unmangle merge --- libraries/entities/src/EntityTree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a1b2af08c0..96cb638d1f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1025,7 +1025,6 @@ void EntityTree::fixupMissingParents() { bool doMove = false; if (entity->isParentIDValid()) { // this entity's parent was previously not known, and now is. Update its location in the EntityTree... - iter.remove(); doMove = true; } else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) { // this is a child of an avatar, which the entity server will never have From 1f8a55da3abbaec197ab407dc949e396596b1405 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Mar 2016 11:36:44 -0700 Subject: [PATCH 223/258] dynamic is the same as grabbable-by-default --- examples/html/entityProperties.html | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index ae42ea7caf..139d5cef67 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -243,12 +243,6 @@ } - function isGrabbableByDefault(properties) { - return properties.type == "Box" || - properties.type == "Sphere" || - properties.dynamic - } - function userDataChanger(groupName, keyName, checkBoxElement, userDataElement, defaultValue) { var properties = {}; var parsedData = {}; @@ -571,7 +565,7 @@ elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; // boxes and sphere are grabbable by default - elGrabbable.checked = isGrabbableByDefault(properties); + elGrabbable.checked = properties.dynamic; elWantsTrigger.checked = false; elIgnoreIK.checked = false; var parsedUserData = {} @@ -820,7 +814,7 @@ }); elGrabbable.addEventListener('change', function() { - userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, isGrabbableByDefault(properties)); + userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, properties.dynamic); }); elWantsTrigger.addEventListener('change', function() { userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); From d811c4f6b53ff7abf18fc7539b658aaff0947067 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Mar 2016 11:39:56 -0700 Subject: [PATCH 224/258] dynamic is the same as grabbable-by-default --- examples/html/entityProperties.html | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 139d5cef67..e3a64da5d4 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -564,7 +564,6 @@ elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; - // boxes and sphere are grabbable by default elGrabbable.checked = properties.dynamic; elWantsTrigger.checked = false; elIgnoreIK.checked = false; From 2834ff29352eab2b368c5a851e5c513d7ed5236c Mon Sep 17 00:00:00 2001 From: Mark Johnson Date: Mon, 14 Mar 2016 11:45:05 -0700 Subject: [PATCH 225/258] Change Q: -> Pending: --- interface/resources/qml/Stats.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index f6d4f4bdae..696695de68 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -167,7 +167,7 @@ Item { font.pixelSize: root.fontSize visible: root.expanded; text: "Downloads: " + root.downloads + "/" + root.downloadLimit + - ", Q: " + root.downloadsPending; + ", Pending: " + root.downloadsPending; } } } From fbc19ec74fde27f3de2aed0c89866581927a2f96 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 14 Mar 2016 12:11:17 -0700 Subject: [PATCH 226/258] Back to the previous comuputation for the eye position in the hope to fix local lighting in stereo --- libraries/gpu/src/gpu/Transform.slh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index e4f8f5dd87..5881b18066 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -101,7 +101,10 @@ TransformObject getTransformObject() { <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; - <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); + vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); + <$eyePos$> = (<$cameraTransform$>._view * _worldpos); + = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); !> } <@endfunc@> From e8a03b725fc5ff06042bd9d0c7eec7f6e82fad0d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Mar 2016 13:03:27 -0700 Subject: [PATCH 227/258] try again on queryAACube --- libraries/shared/src/SpatiallyNestable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 10d851ec5a..3392e9c66d 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -781,6 +781,7 @@ void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) { if (queryAACube.getScale() > 0.0f) { _queryAACubeSet = true; } + checkAndAdjustQueryAACube(); } bool SpatiallyNestable::queryAABoxNeedsUpdate() const { From 1a17de6dbbe18f9595309ad1ef0c80b31412b526 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 14 Mar 2016 14:02:25 -0700 Subject: [PATCH 228/258] reduce log spam --- libraries/entities/src/EntityItem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3c918a0a77..b79fd7107d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -515,7 +515,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // we can confidently ignore this packet EntityTreePointer tree = getTree(); if (tree && tree->isDeletedEntity(_id)) { - qDebug() << "Recieved packet for previously deleted entity [" << _id << "] ignoring. (inside " << __FUNCTION__ << ")"; + #ifdef WANT_DEBUG + qDebug() << "Recieved packet for previously deleted entity [" << _id << "] ignoring. " + "(inside " << __FUNCTION__ << ")"; + #endif ignoreServerPacket = true; } From 7858b6b0cd2cc3c52eafed980598905ba41a8816 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 14 Mar 2016 15:02:01 -0700 Subject: [PATCH 229/258] fix for slow start initial value with new randomization --- libraries/networking/src/udt/CongestionControl.cpp | 7 +++---- libraries/networking/src/udt/CongestionControl.h | 9 +++++++-- libraries/networking/src/udt/Connection.cpp | 7 +++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index c1feae3911..0f8a9f24f6 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -34,7 +34,6 @@ void CongestionControl::setPacketSendPeriod(double newSendPeriod) { } DefaultCC::DefaultCC() : - _slowStartLastAck(_sendCurrSeqNum), _lastDecreaseMaxSeq(SequenceNumber {SequenceNumber::MAX }) { _mss = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; @@ -63,11 +62,11 @@ void DefaultCC::onACK(SequenceNumber ackNum) { if (_slowStart) { // we are in slow start phase - increase the congestion window size by the number of packets just ACKed - _congestionWindowSize += seqlen(_slowStartLastAck, ackNum); + _congestionWindowSize += seqlen(_slowStartLastACK, ackNum); // update the last ACK - _slowStartLastAck = ackNum; - + _slowStartLastACK = ackNum; + // check if we can get out of slow start (is our new congestion window size bigger than the max) if (_congestionWindowSize > _maxCongestionWindowSize) { _slowStart = false; diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index fa1bf73ecf..5fd784cc20 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -50,6 +50,7 @@ protected: void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } void setMaxBandwidth(int maxBandwidth) { _maxBandwidth = maxBandwidth; } + virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) = 0; void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } void setReceiveRate(int rate) { _receiveRate = rate; } void setRTT(int rtt) { _rtt = rtt; } @@ -104,14 +105,18 @@ public: virtual void onACK(SequenceNumber ackNum); virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd); virtual void onTimeout(); - + +protected: + virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) { _slowStartLastACK = seqNum; } + private: void stopSlowStart(); // stops the slow start on loss or timeout p_high_resolution_clock::time_point _lastRCTime = p_high_resolution_clock::now(); // last rate increase time bool _slowStart { true }; // if in slow start phase - SequenceNumber _slowStartLastAck; // last ACKed seq num + bool _hasSetSlowStartACK { false }; // flag to signal if slow start ACK has been set with handshake sequence number + SequenceNumber _slowStartLastACK; // last ACKed seq num from previous slow start check bool _loss { false }; // if loss happened since last rate increase SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened double _lastDecreasePeriod { 1 }; // value of _packetSendPeriod when last decrease happened diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e6a15aa6a0..95afbedb86 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -104,6 +104,9 @@ SendQueue& Connection::getSendQueue() { _sendQueue->setSyncInterval(_synInterval); _sendQueue->setEstimatedTimeout(estimatedTimeout()); _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + + // give the randomized sequence number to the congestion control object + _congestionControl->setInitialSendSequenceNumber(_sendQueue->getCurrentSequenceNumber()); } return *_sendQueue; @@ -282,7 +285,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // grab the up to date packet receive speed and estimated bandwidth int32_t packetReceiveSpeed = _receiveWindow.getPacketReceiveSpeed(); int32_t estimatedBandwidth = _receiveWindow.getEstimatedBandwidth(); - + // update those values in our connection stats _stats.recordReceiveRate(packetReceiveSpeed); _stats.recordEstimatedBandwidth(estimatedBandwidth); @@ -541,7 +544,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // read the ACK sub-sequence number SequenceNumber currentACKSubSequenceNumber; controlPacket->readPrimitive(¤tACKSubSequenceNumber); - + // Check if we need send an ACK2 for this ACK // This will be the case if it has been longer than the sync interval OR // it looks like they haven't received our ACK2 for this ACK From 7823882aa16ad1c11265fd282cffe6bf166f25e2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 14 Mar 2016 16:13:33 -0700 Subject: [PATCH 230/258] Add atp filename to entities added to world --- interface/resources/qml/AssetServer.qml | 12 ++++++------ libraries/entities/src/EntityScriptingInterface.cpp | 3 ++- libraries/entities/src/EntityScriptingInterface.h | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 82970011a0..17e6214a26 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -137,19 +137,19 @@ Window { ); } - function addToWorld(url) { - if (!url) { - url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); - } + function addToWorld() { + var url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); if (!url || !canAddToWorld(url)) { return; } - console.log("Asset browser - adding asset " + url + " to world."); + var name = assetProxyModel.data(treeView.selection.currentIndex); + + console.log("Asset browser - adding asset " + url + " (" + name + ") to world."); var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); - Entities.addModelEntity(url, addPosition); + Entities.addModelEntity(name, url, addPosition); } function copyURLToClipboard(index) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 44da37b0c1..ae538b26c7 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -178,9 +178,10 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties return id; } -QUuid EntityScriptingInterface::addModelEntity(const QString& modelUrl, const glm::vec3& position) { +QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const glm::vec3& position) { EntityItemProperties properties; properties.setType(EntityTypes::Model); + properties.setName(name); properties.setModelURL(modelUrl); properties.setPosition(position); return addEntity(properties); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index fda2aa7e59..b65bc55dbb 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -84,7 +84,8 @@ public slots: /// adds a model with the specific properties Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties); - Q_INVOKABLE QUuid addModelEntity(const QString& modelUrl, const glm::vec3& position); + /// temporary method until addEntity can be used from QJSEngine + Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const glm::vec3& position); /// gets the current model properties for a specific model /// this function will not find return results in script engine contexts which don't have access to models From d18f988cba6f67633a9b9034ab1f123bc5527588 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Mar 2016 17:07:35 -0700 Subject: [PATCH 231/258] namechange URCHIN --> ANEMONE --- .../Home/fishTank/createFishTank.js | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js index 3c168fc668..07d62643c5 100644 --- a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js +++ b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js @@ -1,12 +1,12 @@ // // createTank.js -// +// // // created by James b. Pollack @imgntn on 3/9/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Adds a fish tank and base, decorations, particle bubble systems, and a bubble sound. Attaches a script that does fish swimming. -// +// Copyright 2016 High Fidelity, Inc. +// +// Adds a fish tank and base, decorations, particle bubble systems, and a bubble sound. Attaches a script that does fish swimming. +// // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // @@ -76,14 +76,14 @@ var BUBBLE_SOUND_URL = "http://hifi-content.s3.amazonaws.com/DomainContent/Home/ var bubbleSound = SoundCache.getSound(BUBBLE_SOUND_URL); -var URCHIN_FORWARD_OFFSET = TANK_DIMENSIONS.x - 0.35; -var URCHIN_LATERAL_OFFSET = -0.05; -var URCHIN_VERTICAL_OFFSET = -0.12; +var ANEMONE_FORWARD_OFFSET = TANK_DIMENSIONS.x - 0.35; +var ANEMONE_LATERAL_OFFSET = -0.05; +var ANEMONE_VERTICAL_OFFSET = -0.12; -var URCHIN_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; -var URCHIN_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; -var URCHIN_DIMENSIONS = { +var ANEMONE_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; +var ANEMONE_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; +var ANEMONE_DIMENSIONS = { x: 0.4, y: 0.4, z: 0.4 @@ -311,12 +311,12 @@ function createRocks() { } function createUrchin() { - var finalPosition = getOffsetFromTankCenter(URCHIN_VERTICAL_OFFSET, URCHIN_FORWARD_OFFSET, URCHIN_LATERAL_OFFSET); + var finalPosition = getOffsetFromTankCenter(ANEMONE_VERTICAL_OFFSET, ANEMONE_FORWARD_OFFSET, ANEMONE_LATERAL_OFFSET); var properties = { name: 'hifi-home-fishtank-urchin', type: 'Model', - animationURL: URCHIN_ANIMATION_URL, + animationURL: ANEMONE_ANIMATION_URL, animationIsPlaying: true, animationFPS: 15, animationSettings: JSON.stringify({ @@ -326,11 +326,11 @@ function createUrchin() { startAutomatically: true }), parentID: fishTank, - modelURL: URCHIN_MODEL_URL, + modelURL: ANEMONE_MODEL_URL, position: finalPosition, shapeType: 'Sphere', rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), - dimensions: URCHIN_DIMENSIONS + dimensions: ANEMONE_DIMENSIONS } urchin = Entities.addEntity(properties); @@ -467,4 +467,4 @@ function getEntityCustomData(customKey, id, defaultValue) { } else { return defaultValue; } -} \ No newline at end of file +} From cb62af770f414473b1975443125c252bdb182b94 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Mar 2016 17:10:33 -0700 Subject: [PATCH 232/258] namechange urchin --> anemone --- .../DomainContent/Home/fishTank/createFishTank.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js index 07d62643c5..1a4c95c622 100644 --- a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js +++ b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js @@ -12,7 +12,7 @@ // -var fishTank, tankBase, bubbleSystem, secondBubbleSystem, thirdBubbleSystem, innerContainer, bubbleInjector, lowerCorner, upperCorner, urchin, treasure, rocks; +var fishTank, tankBase, bubbleSystem, secondBubbleSystem, thirdBubbleSystem, innerContainer, bubbleInjector, lowerCorner, upperCorner, anemone, treasure, rocks; var CLEANUP = true; var TANK_DIMENSIONS = { @@ -314,7 +314,7 @@ function createUrchin() { var finalPosition = getOffsetFromTankCenter(ANEMONE_VERTICAL_OFFSET, ANEMONE_FORWARD_OFFSET, ANEMONE_LATERAL_OFFSET); var properties = { - name: 'hifi-home-fishtank-urchin', + name: 'hifi-home-fishtank-anemone', type: 'Model', animationURL: ANEMONE_ANIMATION_URL, animationIsPlaying: true, @@ -333,7 +333,7 @@ function createUrchin() { dimensions: ANEMONE_DIMENSIONS } - urchin = Entities.addEntity(properties); + anemone = Entities.addEntity(properties); } @@ -416,7 +416,7 @@ function cleanup() { Entities.deleteEntity(innerContainer); Entities.deleteEntity(lowerCorner); Entities.deleteEntity(upperCorner); - Entities.deleteEntity(urchin); + Entities.deleteEntity(anemone); Entities.deleteEntity(rocks); bubbleInjector.stop(); bubbleInjector = null; From 16a57bda819b7ce62247535cc030fde7b0e0c6ed Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 14 Mar 2016 17:30:53 -0700 Subject: [PATCH 233/258] SwingTwistConstriant: fix for bad index. --- libraries/animation/src/SwingTwistConstraint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index 72659ff09d..d6d8c87344 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -249,7 +249,7 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir int rightIndex = 0; for (int i = 0; i < numLimits; ++i) { float theta = (float)i * deltaTheta; - int leftIndex = (rightIndex - 1) % numLimits; + int leftIndex = (rightIndex - 1 + numLimits) % numLimits; while (rightIndex < numLimits && theta > limits[rightIndex]._theta) { leftIndex = rightIndex++; } From ff0862b5944bc3ce1bc816fc85f1bafe750e6610 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 14 Mar 2016 14:41:08 -0700 Subject: [PATCH 234/258] Emplace render engine jobs --- libraries/render/src/render/Task.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 7d74529b64..eabdc99338 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -240,7 +240,9 @@ public: const Varying getInput() const { return _input; } const Varying getOutput() const { return _output; } - Model(const Varying& input, Data data = Data()) : Concept(std::make_shared()), _data(data), _input(input), _output(Output()) { + template + Model(const Varying& input, A&&... args) : + Concept(std::make_shared()), _data(Data(std::forward(args)...)), _input(input), _output(Output()) { applyConfiguration(); } @@ -308,7 +310,10 @@ public: const Varying getInput() const { return _input; } const Varying getOutput() const { return _output; } - Model(const Varying& input, Data data = Data()) : Concept(data._config), _data(data), _input(input), _output(Output()) { + template + Model(const Varying& input, A&&... args) : + Concept(nullptr), _data(Data(std::forward(args)...)), _input(input), _output(Output()) { + _config = _data._config; std::static_pointer_cast(_config)->init(&_data); applyConfiguration(); } @@ -337,9 +342,7 @@ public: // Create a new job in the container's queue; returns the job's output template const Varying addJob(std::string name, const Varying& input, A&&... args) { - _jobs.emplace_back(name, std::make_shared( - input, - typename T::JobModel::Data(std::forward(args)...))); + _jobs.emplace_back(name, std::make_shared(input, std::forward(args)...)); QConfigPointer config = _jobs.back().getConfiguration(); config->setParent(_config.get()); config->setObjectName(name.c_str()); From 5ab21588f23180a32ae75656c7890be2dd7aee24 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 14 Mar 2016 14:42:11 -0700 Subject: [PATCH 235/258] Add gpu timer to background --- .../render-utils/src/RenderDeferredTask.cpp | 4 ++++ .../render-utils/src/RenderDeferredTask.h | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f87ca26df1..ba5b2a59d5 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -291,6 +291,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderArgs* args = renderContext->args; doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; + _gpuTimer.begin(batch); auto lightingFBO = DependencyManager::get()->getLightingFramebuffer(); @@ -310,8 +311,11 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const batch.setViewTransform(viewMat); renderItems(sceneContext, renderContext, inItems); + _gpuTimer.end(batch); }); args->_batch = nullptr; + + std::static_pointer_cast(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage(); } void Blit::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index bbcaec34f3..0125ef79fe 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -82,11 +82,27 @@ protected: static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable }; +class DrawBackgroundDeferredConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(double gpuTime READ getGpuTime) +public: + double getGpuTime() { return gpuTime; } + +protected: + friend class DrawBackgroundDeferred; + double gpuTime; +}; + class DrawBackgroundDeferred { public: + using Config = DrawBackgroundDeferredConfig; + using JobModel = render::Job::ModelI; + + void configure(const Config& config) {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemBounds& inItems); - using JobModel = render::Job::ModelI; +protected: + gpu::RangeTimer _gpuTimer; }; class DrawOverlay3DConfig : public render::Job::Config { From 0ea70f234fd83ac9dfe7bd3bc327ee5e81001dcc Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 14 Mar 2016 17:49:17 -0700 Subject: [PATCH 236/258] Add bg gpu timer display --- examples/utilities/tools/render/BG.qml | 22 ++++++++++++++++++++++ examples/utilities/tools/render/debugBG.js | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 examples/utilities/tools/render/BG.qml create mode 100644 examples/utilities/tools/render/debugBG.js diff --git a/examples/utilities/tools/render/BG.qml b/examples/utilities/tools/render/BG.qml new file mode 100644 index 0000000000..40ce5a89fe --- /dev/null +++ b/examples/utilities/tools/render/BG.qml @@ -0,0 +1,22 @@ +// +// BG.qml +// examples/utilities/tools/render +// +// Created by Zach Pomerantz on 2/8/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Item { + Timer { + running: true; repeat: true + onTriggered: time.text = Render.getConfig("DrawBackgroundDeferred").gpuTime + } + + Text { id: time; font.pointSize: 20 } +} + diff --git a/examples/utilities/tools/render/debugBG.js b/examples/utilities/tools/render/debugBG.js new file mode 100644 index 0000000000..21fe024c32 --- /dev/null +++ b/examples/utilities/tools/render/debugBG.js @@ -0,0 +1,21 @@ +// +// debugBG.js +// examples/utilities/tools/render +// +// Zach Pomerantz, created on 1/27/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// Set up the qml ui +var qml = Script.resolvePath('BG.qml'); +var window = new OverlayWindow({ + title: 'Background Timer', + source: qml, + width: 300 +}); +window.setPosition(25, 50); +window.closed.connect(function() { Script.stop(); }); + From 605474a32c6fad56f2c7508b98cd5bec762b7fe3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 14 Mar 2016 18:11:34 -0700 Subject: [PATCH 237/258] actually use the JSONTypePair alias --- interface/src/assets/ATPAssetMigrator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/assets/ATPAssetMigrator.h b/interface/src/assets/ATPAssetMigrator.h index c1becb9c7f..edb12f6e5d 100644 --- a/interface/src/assets/ATPAssetMigrator.h +++ b/interface/src/assets/ATPAssetMigrator.h @@ -51,7 +51,7 @@ private: using JSONTypePair = std::pair; - QMultiHash> _pendingReplacements; + QMultiHash _pendingReplacements; QHash _uploadedAssets; QHash _originalURLs; QSet _ignoredUrls; From 8cb602173ad0241d080e38ca484eed063006551e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 14 Mar 2016 20:54:41 -0700 Subject: [PATCH 238/258] remove the unused member variable --- libraries/networking/src/udt/CongestionControl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 5fd784cc20..69b7a32d2d 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -115,7 +115,6 @@ private: p_high_resolution_clock::time_point _lastRCTime = p_high_resolution_clock::now(); // last rate increase time bool _slowStart { true }; // if in slow start phase - bool _hasSetSlowStartACK { false }; // flag to signal if slow start ACK has been set with handshake sequence number SequenceNumber _slowStartLastACK; // last ACKed seq num from previous slow start check bool _loss { false }; // if loss happened since last rate increase SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened From 010aaa55c0ccf1e347f4b5360fe22e7e8b1412bb Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 14 Mar 2016 22:13:26 -0700 Subject: [PATCH 239/258] const ref --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- libraries/entities-renderer/src/EntityTreeRenderer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index fc06ebabb2..cbb2abea90 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -157,7 +157,7 @@ void EntityTreeRenderer::update() { deleteReleasedModels(); } -bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(glm::vec3& avatarPosition, QVector* entitiesContainingAvatar) { +bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector* entitiesContainingAvatar) { bool didUpdate = false; float radius = 1.0f; // for now, assume 1 meter radius QVector foundEntities; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index b2a2d436c4..8534be852d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -124,7 +124,7 @@ protected: private: void addEntityToScene(EntityItemPointer entity); - bool findBestZoneAndMaybeContainingEntities(glm::vec3& avatarPosition, QVector* entitiesContainingAvatar); + bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector* entitiesContainingAvatar); void applyZonePropertiesToScene(std::shared_ptr zone); void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false); From 98851679c5d029e5087d8414c01b88d4c087e79d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 14 Mar 2016 13:23:33 -0700 Subject: [PATCH 240/258] Remove unused AssetMappingItem --- .../src/scripting/AssetMappingsScriptingInterface.cpp | 8 -------- .../src/scripting/AssetMappingsScriptingInterface.h | 10 ---------- 2 files changed, 18 deletions(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index d4f5431d32..313bfca905 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -169,14 +169,6 @@ bool AssetMappingModel::isKnownFolder(QString path) const { return false; } -AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) : - name(name), - fullPath(fullPath), - isFolder(isFolder) -{ - -} - static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); void AssetMappingModel::refresh() { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 9a427a05ed..d1840e33c0 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -20,16 +20,6 @@ #include #include - class AssetMappingItem : public QStandardItem { - public: - AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); - - QString name; - QString fullPath; - bool isFolder; - }; - - class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: From 9b8b1d41e30a8ad8a5aa772c738ae87697b1ddf6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 08:41:25 -0700 Subject: [PATCH 241/258] Edit in place --- interface/resources/qml/AssetServer.qml | 27 ++++++ interface/resources/qml/controls-uit/Tree.qml | 92 +++++++++++++++++-- 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 82970011a0..453ecfeb6c 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -164,6 +164,28 @@ Window { Window.copyToClipboard(url); } + function renameEl(index, data) { + if (!index) { + return false; + } + + var path = assetProxyModel.data(index, 0x100); + if (!path) { + return false; + } + + var destinationPath = path.split('/'); + destinationPath[destinationPath.length - (path[path.length - 1] === '/' ? 2 : 1)] = data; + destinationPath = destinationPath.join('/').trim(); + + console.log("Renaming " + path + " to " + destinationPath); + if (path === destinationPath) { + return; + } + if (!fileExists(destinationPath)) { + doRenameFile(path, destinationPath); + } + } function renameFile(index) { if (!index) { index = treeView.selection.currentIndex; @@ -371,8 +393,13 @@ Window { height: 400 treeModel: assetProxyModel colorScheme: root.colorScheme + canEdit: true + anchors.left: parent.left anchors.right: parent.right + + modifyEl: renameEl + MouseArea { propagateComposedEvents: true anchors.fill: parent diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index a2572a2f5c..2dfa289096 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -19,9 +19,12 @@ TreeView { id: treeView property var treeModel: ListModel { } + property var canEdit: false property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + property var modifyEl: function(index, data) { return false; } + model: treeModel selection: ItemSelectionModel { model: treeModel @@ -124,7 +127,9 @@ TreeView { : (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd) } - itemDelegate: FiraSansSemiBold { + itemDelegate: Loader { + id: itemDelegateLoader + anchors { left: parent ? parent.left : undefined leftMargin: (2 + styleData.depth) * hifi.dimensions.tablePadding @@ -133,11 +138,86 @@ TreeView { verticalCenter: parent ? parent.verticalCenter : undefined } - text: styleData.value - size: hifi.fontSizes.tableText - color: colorScheme == hifi.colorSchemes.light - ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) - : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) + function getComponent() { + if (treeView.canEdit && styleData.selected) { + return textFieldComponent; + } else { + return labelComponent; + } + + } + sourceComponent: getComponent() + + Component { + id: labelComponent + FiraSansSemiBold { + + text: styleData.value + size: hifi.fontSizes.tableText + color: colorScheme == hifi.colorSchemes.light + ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) + : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) + } + } + Component { + id: textFieldComponent + + TextField { + id: textField + readOnly: !activeFocus + + text: styleData.value + + FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } + font.family: firaSansSemiBold.name + font.pixelSize: hifi.fontSizes.textFieldInput + height: hifi.dimensions.tableRowHeight + + style: TextFieldStyle { + textColor: readOnly + ? hifi.colors.black + : (treeView.isLightColorScheme ? hifi.colors.black : hifi.colors.white) + background: Rectangle { + visible: !readOnly + color: treeView.isLightColorScheme ? hifi.colors.white : hifi.colors.black + border.color: hifi.colors.primaryHighlight + border.width: 1 + } + selectedTextColor: hifi.colors.black + selectionColor: hifi.colors.primaryHighlight + padding.left: readOnly ? 0 : hifi.dimensions.textPadding + padding.right: readOnly ? 0 : hifi.dimensions.textPadding + } + + validator: RegExpValidator { + regExp: /[^/]+/ + } + + Keys.onPressed: { + if (event.key == Qt.Key_Escape) { + text = styleData.value; + unfocusHelper.forceActiveFocus(); + event.accepted = true; + } + } + onAccepted: { + console.log("Data " + acceptableInput + " " + styleData.selected); + console.log("Index " + selection.currentIndex + " " + styleData.index); + if (acceptableInput && styleData.selected) { + console.log("Accepted " + styleData.index + " " + text); + if (!modifyEl(selection.currentIndex, text)) { + text = styleData.value; + } + unfocusHelper.forceActiveFocus(); + } + } + } + } + } + + Item { + id: unfocusHelper + visible: false } onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index) From 07d2213628ca06b6096c2ffc2df2d1c0977429cd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 08:42:55 -0700 Subject: [PATCH 242/258] Remove debug --- interface/resources/qml/AssetServer.qml | 1 - interface/resources/qml/controls-uit/Tree.qml | 3 --- 2 files changed, 4 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 453ecfeb6c..86ccae6f3e 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -178,7 +178,6 @@ Window { destinationPath[destinationPath.length - (path[path.length - 1] === '/' ? 2 : 1)] = data; destinationPath = destinationPath.join('/').trim(); - console.log("Renaming " + path + " to " + destinationPath); if (path === destinationPath) { return; } diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index 2dfa289096..6d4d202e2c 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -201,10 +201,7 @@ TreeView { } } onAccepted: { - console.log("Data " + acceptableInput + " " + styleData.selected); - console.log("Index " + selection.currentIndex + " " + styleData.index); if (acceptableInput && styleData.selected) { - console.log("Accepted " + styleData.index + " " + text); if (!modifyEl(selection.currentIndex, text)) { text = styleData.value; } From 7947bd77241fcceed9fe16c0d1ce3ce4b10a6877 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 15 Mar 2016 10:11:53 -0700 Subject: [PATCH 243/258] Fix message typo enter => entering --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index f75a597733..64a378e14d 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -61,7 +61,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback) { static const QString helpText = - "Upload your asset to a specific folder by enter the full path. Specifying " + "Upload your asset to a specific folder by entering the full path. Specifying " "a new folder name will automatically create that folder for you."; auto offscreenUi = DependencyManager::get(); From 7539eec134fc27811df8b46f2cb900ddc35e6ff5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 15 Mar 2016 10:11:56 -0700 Subject: [PATCH 244/258] Application: fix third-person and fullscreen-mirror toggle --- interface/src/Application.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ce8f4e48d9..e1f2b2a49b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2058,18 +2058,21 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::MiniMirror); } else { - Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)); - if (!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { + bool isMirrorChecked = Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); + Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !isMirrorChecked); + if (isMirrorChecked) { Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); } cameraMenuChanged(); } break; - case Qt::Key_P: - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)); - cameraMenuChanged(); - break; + case Qt::Key_P: { + bool isFirstPersonChecked = Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson); + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !isFirstPersonChecked); + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, isFirstPersonChecked); + cameraMenuChanged(); + break; + } case Qt::Key_Slash: Menu::getInstance()->triggerOption(MenuOption::Stats); From 4a90ec303c7293d58981e8ee3b24c5c1bcb459f0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 11:22:42 -0700 Subject: [PATCH 245/258] Fix drag&drop --- interface/resources/qml/AssetServer.qml | 40 ++++++++++--------- interface/src/Application.cpp | 3 +- interface/src/Application.h | 2 + .../AssetMappingsScriptingInterface.h | 1 + 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index d1b38eccc6..3e8942c206 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -45,6 +45,7 @@ Window { } Component.onCompleted: { + ApplicationInterface.uploadRequest.connect(uploadClicked); assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); reload(); } @@ -245,24 +246,14 @@ Window { Timer { id: timer } - function uploadClicked() { + function uploadClicked(fileUrl) { if (uploadOpen) { return; } uploadOpen = true; - var fileUrl = ""; - - var browser = desktop.fileDialog({ - selectDirectory: false, - dir: currentDirectory - }); - browser.canceled.connect(function() { - uploadOpen = false; - }); - browser.selectedFile.connect(function(url){ + function doUpload(url) { var fileUrl = fileDialogHelper.urlToPath(url); - currentDirectory = browser.dir; var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; @@ -299,8 +290,24 @@ Window { uploadButton.enabled = true; uploadOpen = false; } - }) - }); + }); + } + + if (fileUrl) { + doUpload(fileUrl); + } else { + var browser = desktop.fileDialog({ + selectDirectory: false, + dir: currentDirectory + }); + browser.canceled.connect(function() { + uploadOpen = false; + }); + browser.selectedFile.connect(function(url) { + currentDirectory = browser.dir; + doUpload(url); + }); + } } function errorMessageBox(message) { @@ -312,10 +319,6 @@ Window { }); } - function itemSelected() { - return treeView.selection.hasSelection() - } - Item { width: pane.contentWidth height: pane.height @@ -457,7 +460,6 @@ Window { height: 30 width: 155 - enabled: fileUrlTextField.text != "" onClicked: uploadClickedTimer.running = true // For some reason trigginer an API that enters diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d7cae2483b..2e459362ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4457,9 +4457,10 @@ void Application::toggleRunningScriptsWidget() { void Application::toggleAssetServerWidget(QString filePath) { static const QUrl url("AssetServer.qml"); auto urlSetter = [=](QQmlContext* context, QObject* newObject){ - newObject->setProperty("currentFileUrl", filePath); + emit uploadRequest(filePath); }; DependencyManager::get()->show(url, "AssetServer", urlSetter); + emit uploadRequest(filePath); } void Application::packageModel() { diff --git a/interface/src/Application.h b/interface/src/Application.h index c70d3412b7..029590966c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -231,6 +231,8 @@ signals: void beforeAboutToQuit(); void activeDisplayPluginChanged(); + void uploadRequest(QString path); + public slots: QVector pasteEntities(float x, float y, float z); bool exportEntities(const QString& filename, const QVector& entityIDs); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 8e5d09cbd1..5b5170f7bb 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -30,6 +30,7 @@ public: bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } bool isKnownFolder(QString path) const; +signals: void errorGettingMappings(QString errorString); private: From 4265ddbd0e5b1c3af3a6330b094ff6735e16c091 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 11:42:48 -0700 Subject: [PATCH 246/258] Can't drop fbx if you can't rez --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2e459362ab..3e9c4f5a5a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4455,6 +4455,10 @@ void Application::toggleRunningScriptsWidget() { } void Application::toggleAssetServerWidget(QString filePath) { + if (!DependencyManager::get()->getThisNodeCanRez()) { + return; + } + static const QUrl url("AssetServer.qml"); auto urlSetter = [=](QQmlContext* context, QObject* newObject){ emit uploadRequest(filePath); From ddc658af5f189c1208a746a3e86eb34e1eba2078 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 15 Mar 2016 12:20:51 -0700 Subject: [PATCH 247/258] After a modelURL change to an existing model, allow the model to be snapped and scaled to the existing entity registration and dimensions. --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c637cf4bb9..e2c7bb56c1 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -48,6 +48,13 @@ RenderableModelEntityItem::~RenderableModelEntityItem() { void RenderableModelEntityItem::setModelURL(const QString& url) { auto& currentURL = getParsedModelURL(); + if (_model && (currentURL != url)) { + // The machinery for updateModelBounds will give existing models the opportunity to fix their translation/rotation/scale/registration. + // The first two are straightforward, but the latter two have guards to make sure they don't happen after they've already been set. + // Here we reset those guards. This doesn't cause the entity values to change -- it just allows the model to match once it comes in. + _model->setScaleToFit(false, getDimensions()); + _model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); + } ModelEntityItem::setModelURL(url); if (currentURL != getParsedModelURL() || !_model) { From 03efde5b3c169ed17f028e436016b719496f855e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Mar 2016 13:53:13 -0700 Subject: [PATCH 248/258] Change text in case of drag and drop. --- interface/resources/qml/AssetServer.qml | 8 ++++---- interface/src/Application.cpp | 10 ++++++---- .../src/scripting/AssetMappingsScriptingInterface.cpp | 11 ++++++++--- .../src/scripting/AssetMappingsScriptingInterface.h | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3e8942c206..37291480b2 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -252,7 +252,7 @@ Window { } uploadOpen = true; - function doUpload(url) { + function doUpload(url, dropping) { var fileUrl = fileDialogHelper.urlToPath(url); var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); @@ -290,11 +290,11 @@ Window { uploadButton.enabled = true; uploadOpen = false; } - }); + }, dropping); } if (fileUrl) { - doUpload(fileUrl); + doUpload(fileUrl, true); } else { var browser = desktop.fileDialog({ selectDirectory: false, @@ -305,7 +305,7 @@ Window { }); browser.selectedFile.connect(function(url) { currentDirectory = browser.dir; - doUpload(url); + doUpload(url, false); }); } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3e9c4f5a5a..fda5a0e72d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4460,11 +4460,13 @@ void Application::toggleAssetServerWidget(QString filePath) { } static const QUrl url("AssetServer.qml"); - auto urlSetter = [=](QQmlContext* context, QObject* newObject){ - emit uploadRequest(filePath); + auto startUpload = [=](QQmlContext* context, QObject* newObject){ + if (!filePath.isEmpty()) { + emit uploadRequest(filePath); + } }; - DependencyManager::get()->show(url, "AssetServer", urlSetter); - emit uploadRequest(filePath); + DependencyManager::get()->show(url, "AssetServer", startUpload); + startUpload(nullptr, nullptr); } void Application::packageModel() { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index b721d3c286..3c95eb007a 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -59,13 +59,18 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback request->start(); } -void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback) { +void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback, bool dropEvent) { static const QString helpText = - "Upload your asset to a specific folder by entering the full path. Specifying " + "Upload your asset to a specific folder by entering the full path. Specifying\n" "a new folder name will automatically create that folder for you."; + static const QString dropHelpText = + "This file will be added to your Asset Server.\n" + "Use the field below to place your file in a specific folder or to rename it.\n" + "Specifying a new folder name will automatically create that folder for you."; auto offscreenUi = DependencyManager::get(); - auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", helpText, mapping); + auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", + dropEvent ? dropHelpText : helpText, mapping); if (!result.isValid()) { completedCallback.call({ -1 }); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 5b5170f7bb..831b30513a 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -54,7 +54,7 @@ public: Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); - Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue()); + Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue(), bool dropEvent = false); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); From 377d89e9d65a0274d0a6e13900c79cb9128b0044 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Tue, 15 Mar 2016 14:08:50 -0700 Subject: [PATCH 249/258] added lifetime to water particle effect --- .../DomainContent/Home/plant/waterCanEntityScript.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unpublishedScripts/DomainContent/Home/plant/waterCanEntityScript.js b/unpublishedScripts/DomainContent/Home/plant/waterCanEntityScript.js index d306cf8b6b..2c50ba6950 100644 --- a/unpublishedScripts/DomainContent/Home/plant/waterCanEntityScript.js +++ b/unpublishedScripts/DomainContent/Home/plant/waterCanEntityScript.js @@ -156,6 +156,7 @@ }, maxParticles: 20000, lifespan: 2, + lifetime: 10000, emitRate: 2000, emitSpeed: .3, speedSpread: 0.1, @@ -239,4 +240,4 @@ // entity scripts always need to return a newly constructed object of our type return new WaterSpout(); -}); \ No newline at end of file +}); From f3daa9e1c58d81e08fde57553d7569255ea0c5c1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Mar 2016 14:35:43 -0700 Subject: [PATCH 250/258] Fixing the lighting issue in stereo --- libraries/entities-renderer/src/textured_particle.slv | 3 ++- libraries/gpu/src/gpu/Context.cpp | 5 +++-- libraries/gpu/src/gpu/Transform.slh | 6 +----- libraries/render-utils/src/DeferredLightingEffect.cpp | 4 +++- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index bbd7a1daa7..d3747d21eb 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -125,7 +125,8 @@ void main(void) { vec4 quadPos = radius * UNIT_QUAD[twoTriID]; vec4 anchorPoint; - <$transformModelToEyePos(cam, obj, inPosition, anchorPoint)$> + vec4 _inPosition = vec4(inPosition, 1.0); + <$transformModelToEyePos(cam, obj, _inPosition, anchorPoint)$> vec4 eyePos = anchorPoint + quadPos; <$transformEyeToClipPos(cam, eyePos, gl_Position)$> diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 46c07e4265..dd26ab2823 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -79,7 +79,7 @@ const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const // Get the viewEyeToWorld matrix form the transformView as passed to the gpu::Batch // this is the "_viewInverse" fed to the shader - // Genetrate the "_view" matrix as wekll forom the xform + // Genetrate the "_view" matrix as well from the xform xformView.getMatrix(_viewInverse); _view = glm::inverse(_viewInverse); @@ -98,6 +98,7 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S // FIXME: If "skybox" the ipd is set to 0 for now, let s try to propose a better solution for this in the future } result._projection = _stereo._eyeProjections[eye]; - result.recomputeDerived(xformView); + result.recomputeDerived(offsetTransform); + return result; } diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 5881b18066..52ddf92158 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -99,12 +99,8 @@ TransformObject getTransformObject() { { // transformModelToEyeAndClipPos vec4 eyeWAPos; <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> - <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; - vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); - <$eyePos$> = (<$cameraTransform$>._view * _worldpos); - = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); !> + <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); } <@endfunc@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 82bd0e73d0..f3fa4a43b2 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -264,7 +264,9 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo deferredTransforms[i].projection = projMats[i]; auto sideViewMat = monoViewMat * glm::inverse(eyeViews[i]); - viewTransforms[i].evalFromRawMatrix(sideViewMat); + // viewTransforms[i].evalFromRawMatrix(sideViewMat); + viewTransforms[i] = monoViewTransform; + viewTransforms[i].postTranslate(-glm::vec3((eyeViews[i][3])));// evalFromRawMatrix(sideViewMat); deferredTransforms[i].viewInverse = sideViewMat; deferredTransforms[i].stereoSide = (i == 0 ? -1.0f : 1.0f); From b8abb1b6ddff30d0d29c986effa832bae323597f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 11:24:22 -0700 Subject: [PATCH 251/258] remove redundant static from const in AssetServer --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ff7d869a0b..4331b3ad31 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -438,7 +438,7 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } -static const QString MAP_FILE_NAME = "map.json"; +const QString MAP_FILE_NAME = "map.json"; void AssetServer::loadMappingsFromFile() { From 29cd487f848eb6bdcd71a450b0f745c5d518910d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 11:26:20 -0700 Subject: [PATCH 252/258] fixes for styling and logging from CR --- assignment-client/src/assets/AssetServer.cpp | 5 ++--- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 3 +-- libraries/script-engine/src/AssetScriptingInterface.cpp | 4 ---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4331b3ad31..d1e51d8545 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -222,8 +222,7 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode auto assetHash = it->toString(); replyPacket.writePrimitive(AssetServerError::NoError); replyPacket.write(QByteArray::fromHex(assetHash.toUtf8())); - } - else { + } else { replyPacket.writePrimitive(AssetServerError::AssetNotFound); } } @@ -578,7 +577,7 @@ bool AssetServer::deleteMappings(AssetPathList& paths) { if (sizeBefore != sizeNow) { qDebug() << "Deleted" << sizeBefore - sizeNow << "mappings in folder: " << path; } else { - qDebug() << "Did not find any mappings in folder:" << path; + qDebug() << "Did not find any mappings to delete in folder:" << path; } } else { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 3c95eb007a..005f8a597c 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -225,8 +225,7 @@ void AssetMappingModel::refresh() { lastItem = item; _pathToItemMap[fullPath] = lastItem; - } - else { + } else { lastItem = it.value(); } } diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index aaa4f97fb3..80cd30a8b6 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -50,10 +50,6 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb auto parts = path.split(".", QString::SkipEmptyParts); auto hash = parts.length() > 0 ? parts[0] : ""; - if (hash.length() != SHA256_HASH_HEX_LENGTH) { - return; - } - auto assetClient = DependencyManager::get(); auto assetRequest = assetClient->createRequest(hash); From b13dff1c771c9969cd55c948fef2836c079d6a40 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 11:49:45 -0700 Subject: [PATCH 253/258] Revert "remove redundant static from const in AssetServer" This reverts commit 0837261d403e844f648f4f4ddcce7d7b79c7083b. --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index d1e51d8545..b63cf41b7c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -437,7 +437,7 @@ void AssetServer::sendStatsPacket() { ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } -const QString MAP_FILE_NAME = "map.json"; +static const QString MAP_FILE_NAME = "map.json"; void AssetServer::loadMappingsFromFile() { From 00129677349bdb451317f2279703870d20eae261 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 11:57:26 -0700 Subject: [PATCH 254/258] use curly braced initialization for consts --- interface/src/Application.cpp | 3 ++- libraries/networking/src/AssetResourceRequest.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fda5a0e72d..4777d86d5e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4459,7 +4459,8 @@ void Application::toggleAssetServerWidget(QString filePath) { return; } - static const QUrl url("AssetServer.qml"); + static const QUrl url { "AssetServer.qml" }; + auto startUpload = [=](QQmlContext* context, QObject* newObject){ if (!filePath.isEmpty()) { emit uploadRequest(filePath); diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index c9063d7eae..6b94ee152a 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -26,7 +26,7 @@ AssetResourceRequest::~AssetResourceRequest() { } bool AssetResourceRequest::urlIsAssetHash() const { - static const QString ATP_HASH_REGEX_STRING = "^atp:([A-Fa-f0-9]{64})(\\.[\\w]+)?$"; + static const QString ATP_HASH_REGEX_STRING { "^atp:([A-Fa-f0-9]{64})(\\.[\\w]+)?$" }; QRegExp hashRegex { ATP_HASH_REGEX_STRING }; return hashRegex.exactMatch(_url.toString()); From 1cd16da83edbd92105ed89dfb20aafebd3c4d0e0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 15:28:55 -0700 Subject: [PATCH 255/258] do sleep timing off when next packet would have been --- libraries/networking/src/udt/SendQueue.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 5c6db5adf3..3149c5c7bf 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -280,11 +280,11 @@ void SendQueue::run() { // Once we're here we've either received the handshake ACK or it's going to be time to re-send a handshake. // Either way let's continue processing - no packets will be sent if no handshake ACK has been received. } - + + // Keep an HRC to know when the next packet should have been + auto nextPacketTimestamp = p_high_resolution_clock::now(); + while (_state == State::Running) { - // Record how long the loop takes to execute - const auto loopStartTimestamp = p_high_resolution_clock::now(); - bool sentAPacket = maybeResendPacket(); // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire @@ -304,9 +304,15 @@ void SendQueue::run() { return; } + // grab the current HRC timestamp + const auto now = p_high_resolution_clock::now(); + + // push the next packet timestamp forwards by the current packet send period + nextPacketTimestamp += std::chrono::microseconds(_packetSendPeriod); + // sleep as long as we need until next packet send, if we can - const auto loopEndTimestamp = p_high_resolution_clock::now(); - const auto timeToSleep = (loopStartTimestamp + std::chrono::microseconds(_packetSendPeriod)) - loopEndTimestamp; + const auto timeToSleep = std::chrono::duration_cast(nextPacketTimestamp - now); + std::this_thread::sleep_for(timeToSleep); } } From 92b287355c4799cae3e11b71ee01e7c2ef0a2631 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 15 Mar 2016 15:56:13 -0700 Subject: [PATCH 256/258] make TRUNCATED_HASH_NUM_CHAR a non-static const --- assignment-client/src/assets/AssetServer.cpp | 42 ++++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index b63cf41b7c..f5f83399d6 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -111,7 +111,7 @@ void AssetServer::completeSetup() { // load whatever mappings we currently have from the local file loadMappingsFromFile(); - + qInfo() << "Serving files from: " << _filesDirectory.path(); // Check the asset directory to output some information about what we have @@ -154,7 +154,7 @@ void AssetServer::performMappingMigration() { qDebug() << "\tRenamed pre-mapping file" << fileInfo.fileName(); // add a new mapping with the old extension and a truncated version of the hash - static const int TRUNCATED_HASH_NUM_CHAR = 16; + const int TRUNCATED_HASH_NUM_CHAR = 16; auto fakeFileName = "/" + hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension; qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash; @@ -330,7 +330,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh void AssetServer::handleAssetGet(QSharedPointer message, SharedNodePointer senderNode) { auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(DataOffset) + sizeof(DataOffset)); - + if (message->getSize() < minSize) { qDebug() << "ERROR bad file request"; return; @@ -342,26 +342,26 @@ void AssetServer::handleAssetGet(QSharedPointer message, Shared } void AssetServer::handleAssetUpload(QSharedPointer message, SharedNodePointer senderNode) { - + if (senderNode->getCanRez()) { qDebug() << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); - + auto task = new UploadAssetTask(message, senderNode, _filesDirectory); _taskPool.start(task); } else { // this is a node the domain told us is not allowed to rez entities // for now this also means it isn't allowed to add assets // so return a packet with error that indicates that - + auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); - + MessageID messageID; message->readPrimitive(&messageID); - + // write the message ID and a permission denied error permissionErrorPacket->writePrimitive(messageID); permissionErrorPacket->writePrimitive(AssetServerError::PermissionDenied); - + // send off the packet auto nodeList = DependencyManager::get(); nodeList->sendPacket(std::move(permissionErrorPacket), *senderNode); @@ -370,19 +370,19 @@ void AssetServer::handleAssetUpload(QSharedPointer message, Sha void AssetServer::sendStatsPacket() { QJsonObject serverStats; - + auto stats = DependencyManager::get()->sampleStatsForAllConnections(); - + for (const auto& stat : stats) { QJsonObject nodeStats; auto endTimeMs = std::chrono::duration_cast(stat.second.endTime); QDateTime date = QDateTime::fromMSecsSinceEpoch(endTimeMs.count()); - + static const float USEC_PER_SEC = 1000000.0f; static const float MEGABITS_PER_BYTE = 8.0f / 1000000.0f; // Bytes => Mbits float elapsed = (float)(stat.second.endTime - stat.second.startTime).count() / USEC_PER_SEC; // sec float megabitsPerSecPerByte = MEGABITS_PER_BYTE / elapsed; // Bytes => Mb/s - + QJsonObject connectionStats; connectionStats["1. Last Heard"] = date.toString(); connectionStats["2. Est. Max (P/s)"] = stat.second.estimatedBandwith; @@ -392,10 +392,10 @@ void AssetServer::sendStatsPacket() { connectionStats["6. Up (Mb/s)"] = stat.second.sentBytes * megabitsPerSecPerByte; connectionStats["7. Down (Mb/s)"] = stat.second.receivedBytes * megabitsPerSecPerByte; nodeStats["Connection Stats"] = connectionStats; - + using Events = udt::ConnectionStats::Stats::Event; const auto& events = stat.second.events; - + QJsonObject upstreamStats; upstreamStats["1. Sent (P/s)"] = stat.second.sendRate; upstreamStats["2. Sent Packets"] = stat.second.sentPackets; @@ -407,7 +407,7 @@ void AssetServer::sendStatsPacket() { upstreamStats["8. Sent ACK2"] = events[Events::SentACK2]; upstreamStats["9. Retransmitted"] = events[Events::Retransmission]; nodeStats["Upstream Stats"] = upstreamStats; - + QJsonObject downstreamStats; downstreamStats["1. Recvd (P/s)"] = stat.second.receiveRate; downstreamStats["2. Recvd Packets"] = stat.second.receivedPackets; @@ -418,7 +418,7 @@ void AssetServer::sendStatsPacket() { downstreamStats["7. Recvd ACK2"] = events[Events::ReceivedACK2]; downstreamStats["8. Duplicates"] = events[Events::Duplicate]; nodeStats["Downstream Stats"] = downstreamStats; - + QString uuid; auto nodelist = DependencyManager::get(); if (stat.first == nodelist->getDomainHandler().getSockAddr()) { @@ -429,10 +429,10 @@ void AssetServer::sendStatsPacket() { uuid = uuidStringWithoutCurlyBraces(node ? node->getUUID() : QUuid()); nodeStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = uuid; } - + serverStats[uuid] = nodeStats; } - + // send off the stats packets ThreadedAssignment::addPacketStatsAndSendStatsPacket(serverStats); } @@ -607,7 +607,7 @@ bool AssetServer::deleteMappings(AssetPathList& paths) { bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) { oldPath = oldPath.trimmed(); newPath = newPath.trimmed(); - + if (!isValidPath(oldPath) || !isValidPath(newPath)) { qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:" << oldPath << "=>" << newPath; @@ -646,7 +646,7 @@ bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) { if (writeMappingsToFile()) { // persisted the changed mappings, return success qDebug() << "Renamed folder mapping:" << oldPath << "=>" << newPath; - + return true; } else { // couldn't persist the renamed paths, rollback and return failure From d58ac269eec8d8a8235c6e4d559964396e35e539 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Mar 2016 17:01:26 -0700 Subject: [PATCH 257/258] Fixing a bug when albedo map transaprent but not quite loaded yet --- .../src/model-networking/ModelCache.cpp | 2 +- .../render-utils/src/model_translucent.slf | 36 ++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 3f7e0405d4..c9ff8e681b 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -147,7 +147,7 @@ bool NetworkGeometry::isLoadedWithTextures() const { (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } - if (material->albedoTexture) { + if (material->albedoTexture && material->albedoTexture->getGPUTexture()) { // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index 086f9fe168..b99b5c8a2a 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -20,7 +20,8 @@ <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> -uniform sampler2D albedoMap; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> in vec2 _texCoord0; in vec4 _position; @@ -31,16 +32,27 @@ in float _alpha; out vec4 _fragColor; void main(void) { - vec4 albedo = texture(albedoMap, _texCoord0); - Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$> + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + float metallic = getMaterialMetallic(mat); + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); - vec3 fragAlbedo = getMaterialAlbedo(mat) * albedo.rgb * _color; - float fragMetallic = getMaterialMetallic(mat); - vec3 fragEmissive = getMaterialEmissive(mat); - float fragRoughness = getMaterialRoughness(mat); - float fragOpacity = getMaterialOpacity(mat) * albedo.a * _alpha; + + float fragOpacity = getMaterialOpacity(mat) * albedoTex.a * _alpha; TransformCamera cam = getTransformCamera(); @@ -50,9 +62,9 @@ void main(void) { 1.0, fragPosition, fragNormal, - fragAlbedo, - fragMetallic, - fragEmissive, - fragRoughness), + albedo, + metallic, + emissive, + roughness), fragOpacity); } From c94e2bdc8b71dcf1925edf76aaef1fa8095c5456 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Mar 2016 08:53:31 -0700 Subject: [PATCH 258/258] grab the now timestamp only when needed --- libraries/networking/src/udt/SendQueue.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 3149c5c7bf..8e5141b58a 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -29,6 +29,7 @@ #include "Socket.h" using namespace udt; +using namespace std::chrono; template class DoubleLock { @@ -303,15 +304,12 @@ void SendQueue::run() { if (_state != State::Running || isInactive(sentAPacket)) { return; } - - // grab the current HRC timestamp - const auto now = p_high_resolution_clock::now(); // push the next packet timestamp forwards by the current packet send period nextPacketTimestamp += std::chrono::microseconds(_packetSendPeriod); // sleep as long as we need until next packet send, if we can - const auto timeToSleep = std::chrono::duration_cast(nextPacketTimestamp - now); + const auto timeToSleep = duration_cast(nextPacketTimestamp - p_high_resolution_clock::now()); std::this_thread::sleep_for(timeToSleep); }