diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 6e3db69c63..9df606c227 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -953,16 +953,15 @@ void AssetServer::removeBakedPathsForDeletedAsset(AssetHash hash) { deleteMappings(hiddenBakedFolder); } -bool AssetServer::deleteMappings(AssetPathList& paths) { +bool AssetServer::deleteMappings(const AssetPathList& paths) { // take a copy of the current mappings in case persistence of these deletes fails auto oldMappings = _fileMappings; QSet hashesToCheckForDeletion; // enumerate the paths to delete and remove them all - for (auto& path : paths) { - - path = path.trimmed(); + for (const auto& rawPath : paths) { + auto path = rawPath.trimmed(); // figure out if this path will delete a file or folder if (pathIsFolder(path)) { @@ -991,12 +990,12 @@ bool AssetServer::deleteMappings(AssetPathList& paths) { } else { auto it = _fileMappings.find(path); if (it != _fileMappings.end()) { - _fileMappings.erase(it); - // add this hash to the list we need to check for asset removal from server hashesToCheckForDeletion << it->second; qCDebug(asset_server) << "Deleted a mapping:" << path << "=>" << it->second; + + _fileMappings.erase(it); } else { qCDebug(asset_server) << "Unable to delete a mapping that was not found:" << path; } @@ -1165,10 +1164,11 @@ void AssetServer::handleFailedBake(QString originalAssetHash, QString assetPath, void AssetServer::handleCompletedBake(QString originalAssetHash, QString originalAssetPath, QVector bakedFilePaths) { bool errorCompletingBake { false }; + QString errorReason; qDebug() << "Completing bake for " << originalAssetHash; - for (auto& filePath: bakedFilePaths) { + for (auto& filePath : bakedFilePaths) { // figure out the hash for the contents of this file QFile file(filePath); @@ -1184,6 +1184,7 @@ void AssetServer::handleCompletedBake(QString originalAssetHash, QString origina } else { // stop handling this bake, couldn't hash the contents of the file errorCompletingBake = true; + errorReason = "Failed to finalize bake"; break; } @@ -1194,6 +1195,7 @@ void AssetServer::handleCompletedBake(QString originalAssetHash, QString origina if (!file.copy(_filesDirectory.absoluteFilePath(bakedFileHash))) { // stop handling this bake, couldn't copy the bake file into our files directory errorCompletingBake = true; + errorReason = "Failed to copy baked assets to asset server"; break; } } @@ -1220,12 +1222,14 @@ void AssetServer::handleCompletedBake(QString originalAssetHash, QString origina qDebug() << "Failed to set mapping"; // stop handling this bake, couldn't add a mapping for this bake file errorCompletingBake = true; + errorReason = "Failed to finalize bake"; break; } } else { qDebug() << "Failed to open baked file: " << filePath; // stop handling this bake, we couldn't open one of the files for reading errorCompletingBake = true; + errorReason = "Failed to finalize bake"; break; } } @@ -1235,6 +1239,10 @@ void AssetServer::handleCompletedBake(QString originalAssetHash, QString origina writeMetaFile(originalAssetHash); } else { qWarning() << "Could not complete bake for" << originalAssetHash; + AssetMeta meta; + meta.failedLastBake = true; + meta.lastBakeErrors = errorReason; + writeMetaFile(originalAssetHash, meta); } _pendingBakes.remove(originalAssetHash); @@ -1246,7 +1254,6 @@ void AssetServer::handleAbortedBake(QString originalAssetHash, QString assetPath } static const QString BAKE_VERSION_KEY = "bake_version"; -static const QString APP_VERSION_KEY = "app_version"; static const QString FAILED_LAST_BAKE_KEY = "failed_last_bake"; static const QString LAST_BAKE_ERRORS_KEY = "last_bake_errors"; @@ -1273,18 +1280,15 @@ std::pair AssetServer::readMetaFile(AssetHash hash) { auto root = doc.object(); auto bakeVersion = root[BAKE_VERSION_KEY].toInt(-1); - auto appVersion = root[APP_VERSION_KEY].toInt(-1); auto failedLastBake = root[FAILED_LAST_BAKE_KEY]; auto lastBakeErrors = root[LAST_BAKE_ERRORS_KEY]; if (bakeVersion != -1 - && appVersion != -1 && failedLastBake.isBool() && lastBakeErrors.isString()) { AssetMeta meta; meta.bakeVersion = bakeVersion; - meta.applicationVersion = appVersion; meta.failedLastBake = failedLastBake.toBool(); meta.lastBakeErrors = lastBakeErrors.toString(); @@ -1303,7 +1307,6 @@ bool AssetServer::writeMetaFile(AssetHash originalAssetHash, const AssetMeta& me QJsonObject metaFileObject; metaFileObject[BAKE_VERSION_KEY] = meta.bakeVersion; - metaFileObject[APP_VERSION_KEY] = meta.applicationVersion; metaFileObject[FAILED_LAST_BAKE_KEY] = meta.failedLastBake; metaFileObject[LAST_BAKE_ERRORS_KEY] = meta.lastBakeErrors; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 10ea067ee5..94be560c9b 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -34,7 +34,6 @@ struct AssetMeta { } int bakeVersion { 0 }; - int applicationVersion { 0 }; bool failedLastBake { false }; QString lastBakeErrors; }; @@ -79,7 +78,7 @@ private: bool setMapping(AssetPath path, AssetHash hash); /// Delete mapping `path`. Returns `true` if deletion of mappings succeeds, else `false`. - bool deleteMappings(AssetPathList& paths); + bool deleteMappings(const AssetPathList& paths); /// Rename mapping from `oldPath` to `newPath`. Returns true if successful bool renameMapping(AssetPath oldPath, AssetPath newPath); diff --git a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml index 83b48094e3..80c1b58444 100644 --- a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml @@ -400,6 +400,17 @@ Rectangle { colorScheme: hifi.colorSchemes.dark anchors.left: parent.left anchors.right: parent.right + + TableViewColumn { + role: "display"; + } + + onActivated: { + var path = scriptsModel.data(index, 0x100) + if (path) { + loadScript(path) + } + } } HifiControls.VerticalSpacer { @@ -426,13 +437,6 @@ Rectangle { } } } - - onActivated: { - var path = scriptsModel.data(index, 0x100) - if (path) { - loadScript(path) - } - } } Item { diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index b5b6570599..3ef291af22 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -583,29 +583,17 @@ void FBXBaker::rewriteAndBakeSceneTextures() { QString fbxTextureFileName { textureChild.properties.at(0).toByteArray() }; QFileInfo textureFileInfo { fbxTextureFileName.replace("\\", "/") }; + if (textureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) { + // re-baking an FBX that already references baked textures is a fail + // so we add an error and return from here + handleError("Cannot re-bake a file that references compressed textures"); + + return; + } + + // make sure this texture points to something and isn't one we've already re-mapped if (!textureFileInfo.filePath().isEmpty()) { - - if (textureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) { - // re-baking an FBX that already references baked textures is a fail - // so we add an error and return from here - handleError("Cannot re-bake a file that references compressed textures"); - - return; - } - - // construct the new baked texture file name and file path - // ensuring that the baked texture will have a unique name - // even if there was another texture with the same name at a different path - auto bakedTextureFileName = createBakedTextureFileName(textureFileInfo); - QString bakedTextureFilePath { - _bakedOutputDir + "/" + bakedTextureFileName - }; - _outputFiles.push_back(bakedTextureFilePath); - - qCDebug(model_baking).noquote() << "Re-mapping" << fbxTextureFileName - << "to" << bakedTextureFileName; - // check if this was an embedded texture we have already have in-memory content for auto textureContent = _textureContent.value(fbxTextureFileName.toLocal8Bit()); @@ -613,10 +601,29 @@ void FBXBaker::rewriteAndBakeSceneTextures() { auto urlToTexture = getTextureURL(textureFileInfo, fbxTextureFileName, !textureContent.isNull()); + QString bakedTextureFileName; + if (_remappedTexturePaths.contains(urlToTexture)) { + bakedTextureFileName = _remappedTexturePaths[urlToTexture]; + } else { + // construct the new baked texture file name and file path + // ensuring that the baked texture will have a unique name + // even if there was another texture with the same name at a different path + bakedTextureFileName = createBakedTextureFileName(textureFileInfo); + _remappedTexturePaths[urlToTexture] = bakedTextureFileName; + } + + qCDebug(model_baking).noquote() << "Re-mapping" << fbxTextureFileName + << "to" << bakedTextureFileName; + + QString bakedTextureFilePath { + _bakedOutputDir + "/" + bakedTextureFileName + }; + // write the new filename into the FBX scene textureChild.properties[0] = bakedTextureFileName.toLocal8Bit(); if (!_bakingTextures.contains(urlToTexture)) { + _outputFiles.push_back(bakedTextureFilePath); // grab the ID for this texture so we can figure out the // texture type from the loaded materials @@ -624,7 +631,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() { auto textureType = textureTypes[textureID]; // bake this texture asynchronously - bakeTexture(urlToTexture, textureType, _bakedOutputDir, textureContent); + bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent); } } } @@ -644,10 +651,10 @@ void FBXBaker::rewriteAndBakeSceneTextures() { } void FBXBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, - const QDir& outputDir, const QByteArray& textureContent) { + const QDir& outputDir, const QString& bakedFilename, const QByteArray& textureContent) { // start a bake for this texture and add it to our list to keep track of QSharedPointer bakingTexture { - new TextureBaker(textureURL, textureType, outputDir, textureContent), + new TextureBaker(textureURL, textureType, outputDir, bakedFilename, textureContent), &TextureBaker::deleteLater }; diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 26471a29b3..ad8284bfa8 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -71,7 +71,7 @@ private: QUrl getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded = false); void bakeTexture(const QUrl& textureURL, image::TextureUsage::Type textureType, const QDir& outputDir, - const QByteArray& textureContent = QByteArray()); + const QString& bakedFilename, const QByteArray& textureContent = QByteArray()); QUrl _fbxURL; @@ -91,6 +91,7 @@ private: QMultiHash> _bakingTextures; QHash _textureNameMatchCount; + QHash _remappedTexturePaths; TextureBakerThreadGetter _textureThreadGetter; diff --git a/libraries/baking/src/TextureBaker.cpp b/libraries/baking/src/TextureBaker.cpp index febc7ea092..1a320efabc 100644 --- a/libraries/baking/src/TextureBaker.cpp +++ b/libraries/baking/src/TextureBaker.cpp @@ -26,15 +26,19 @@ const QString BAKED_TEXTURE_EXT = ".ktx"; TextureBaker::TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType, - const QDir& outputDirectory, const QByteArray& textureContent) : + const QDir& outputDirectory, const QString& bakedFilename, + const QByteArray& textureContent) : _textureURL(textureURL), _originalTexture(textureContent), _textureType(textureType), - _outputDirectory(outputDirectory) + _outputDirectory(outputDirectory), + _bakedTextureFileName(bakedFilename) { - // figure out the baked texture filename - auto originalFilename = textureURL.fileName(); - _bakedTextureFileName = originalFilename.left(originalFilename.lastIndexOf('.')) + BAKED_TEXTURE_EXT; + if (bakedFilename.isEmpty()) { + // figure out the baked texture filename + auto originalFilename = textureURL.fileName(); + _bakedTextureFileName = originalFilename.left(originalFilename.lastIndexOf('.')) + BAKED_TEXTURE_EXT; + } } void TextureBaker::bake() { diff --git a/libraries/baking/src/TextureBaker.h b/libraries/baking/src/TextureBaker.h index e5bd41cf0d..b2e86b2b5b 100644 --- a/libraries/baking/src/TextureBaker.h +++ b/libraries/baking/src/TextureBaker.h @@ -28,7 +28,8 @@ class TextureBaker : public Baker { public: TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType, - const QDir& outputDirectory, const QByteArray& textureContent = QByteArray()); + const QDir& outputDirectory, const QString& bakedFilename = QString(), + const QByteArray& textureContent = QByteArray()); static const QStringList getSupportedFormats(); diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index b51e9cd529..55895e31a4 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -54,9 +54,24 @@ float RecordingScriptingInterface::playerLength() const { return _player->length(); } +void RecordingScriptingInterface::playClip(NetworkClipLoaderPointer clipLoader, const QString& url, QScriptValue callback) { + _player->queueClip(clipLoader->getClip()); + + if (callback.isFunction()) { + QScriptValueList args { true, url }; + callback.call(_scriptEngine->globalObject(), args); + } +} + void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue callback) { auto clipLoader = DependencyManager::get()->getClipLoader(url); + if (clipLoader->isLoaded()) { + qCDebug(scriptengine) << "Recording already loaded from" << url; + playClip(clipLoader, url, callback); + return; + } + // hold a strong pointer to the loading clip so that it has a chance to load _clipLoaders.insert(clipLoader); @@ -69,12 +84,7 @@ void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue if (auto clipLoader = weakClipLoader.toStrongRef()) { qCDebug(scriptengine) << "Loaded recording from" << url; - _player->queueClip(clipLoader->getClip()); - - if (callback.isFunction()) { - QScriptValueList args { true, url }; - callback.call(_scriptEngine->globalObject(), args); - } + playClip(clipLoader, url, callback); // drop our strong pointer to this clip so it is cleaned up _clipLoaders.remove(clipLoader); diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index bc0b019251..22e4d30830 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -88,6 +88,9 @@ protected: QSharedPointer _scriptEngine; QSet _clipLoaders; + +private: + void playClip(recording::NetworkClipLoaderPointer clipLoader, const QString& url, QScriptValue callback); }; #endif // hifi_RecordingScriptingInterface_h diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js index 4ad17e6de9..8d093afe2c 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -26,6 +26,7 @@ Script.include("/~/system/libraries/utils.js"); this.previousParentID = {}; this.previousParentJointIndex = {}; this.previouslyUnhooked = {}; + this.robbed = false; this.parameters = makeDispatcherModuleParameters( 90, @@ -111,9 +112,9 @@ Script.include("/~/system/libraries/utils.js"); } else if (this.otherHandIsParent(grabbedProperties)) { // the other hand is parent. Steal the object and information var otherModule = this.getOtherModule(); - this.previousParentID[this.grabbedThingID] = otherModule.previousParentID[this.garbbedThingID]; + this.previousParentID[this.grabbedThingID] = otherModule.previousParentID[this.grabbedThingID]; this.previousParentJointIndex[this.grabbedThingID] = otherModule.previousParentJointIndex[this.grabbedThingID]; - + otherModule.robbed = true; } else { this.previousParentID[this.grabbedThingID] = grabbedProperties.parentID; this.previousParentJointIndex[this.grabbedThingID] = grabbedProperties.parentJointIndex; @@ -134,12 +135,12 @@ Script.include("/~/system/libraries/utils.js"); this.endNearParentingGrabOverlay = function () { var previousParentID = this.previousParentID[this.grabbedThingID]; - if (previousParentID === NULL_UUID || previousParentID === null || previousParentID === undefined) { + if ((previousParentID === NULL_UUID || previousParentID === null) && !this.robbed) { Overlays.editOverlay(this.grabbedThingID, { parentID: NULL_UUID, parentJointIndex: -1 }); - } else { + } else if (!this.robbed){ // before we grabbed it, overlay was a child of something; put it back. Overlays.editOverlay(this.grabbedThingID, { parentID: this.previousParentID[this.grabbedThingID], @@ -170,7 +171,9 @@ Script.include("/~/system/libraries/utils.js"); this.isReady = function (controllerData) { - if (controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) { + if ((controllerData.triggerClicks[this.hand] === 0 && + controllerData.secondaryValues[this.hand] === 0)) { + this.robbed = false; return makeRunningValues(false, [], []); } @@ -182,7 +185,7 @@ Script.include("/~/system/libraries/utils.js"); }); var targetID = this.getTargetID(grabbableOverlays, controllerData); - if (targetID) { + if (targetID && !this.robbed) { this.grabbedThingID = targetID; this.startNearParentingGrabOverlay(controllerData); return makeRunningValues(true, [this.grabbedThingID], []); @@ -194,6 +197,7 @@ Script.include("/~/system/libraries/utils.js"); this.run = function (controllerData) { if (controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) { this.endNearParentingGrabOverlay(); + this.robbed = false; return makeRunningValues(false, [], []); } else { // check if someone stole the target from us