mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-10 10:34:56 +02:00
Display resource-access events in marketplace item tester
Includes refactoring marketplace item tester into a single-page app.
This commit is contained in:
parent
8e5bc1678f
commit
3b15548ea3
39 changed files with 841 additions and 378 deletions
|
@ -222,7 +222,8 @@ void Agent::requestScript() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, scriptURL);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
this, scriptURL, true, -1, "Agent::requestScript");
|
||||
|
||||
if (!request) {
|
||||
qWarning() << "Could not create ResourceRequest for Agent script at" << scriptURL.toString();
|
||||
|
@ -896,7 +897,7 @@ void Agent::aboutToFinish() {
|
|||
{
|
||||
DependencyManager::get<ScriptEngines>()->shutdownScripting();
|
||||
}
|
||||
|
||||
|
||||
DependencyManager::destroy<ScriptEngines>();
|
||||
|
||||
DependencyManager::destroy<AssignmentDynamicFactory>();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Load items not in the marketplace for testing purposes
|
||||
//
|
||||
// Created by Zach Fox on 2018-09-05
|
||||
// Created by Kerry Ivan Kurian on 2018-09-05
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -26,7 +26,9 @@ Rectangle {
|
|||
id: root
|
||||
|
||||
property string installedApps
|
||||
property string resourceAccessEventText
|
||||
property var nextResourceObjectId: 0
|
||||
property var startDate
|
||||
signal sendToScript(var message)
|
||||
|
||||
HifiStylesUit.HifiConstants { id: hifi }
|
||||
|
@ -51,9 +53,28 @@ Rectangle {
|
|||
spinner.visible = false;
|
||||
break;
|
||||
case "nextObjectIdInTest":
|
||||
print("!!!! message from script! " + JSON.stringify(message));
|
||||
nextResourceObjectId = message.id;
|
||||
spinner.visible = false;
|
||||
break;
|
||||
case "resourceRequestEvent":
|
||||
try {
|
||||
var date = new Date(JSON.parse(message.data.date));
|
||||
} catch(err) {
|
||||
print("!!!!! Date conversion failed: " + JSON.stringify(message.data));
|
||||
}
|
||||
// XXX Eventually this date check goes away b/c we will
|
||||
// be able to match up resouce access events to resource
|
||||
// object ids, ignoring those that have -1 resource
|
||||
// object ids.
|
||||
if (date >= startDate) {
|
||||
resourceAccessEventText += (
|
||||
message.data.callerId + " " + message.data.extra +
|
||||
" " + message.data.url +
|
||||
" [" + date.toISOString() + "]\n"
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +85,7 @@ Rectangle {
|
|||
resource.match(/\.json\.gz$/) ? "content set" :
|
||||
resource.match(/\.json$/) ? "entity or wearable" :
|
||||
"unknown");
|
||||
return { "id": nextResourceObjectId++,
|
||||
return { "resourceObjectId": nextResourceObjectId++,
|
||||
"resource": resource,
|
||||
"assetType": assetType };
|
||||
}
|
||||
|
@ -89,153 +110,240 @@ Rectangle {
|
|||
return httpPattern.test(resource) ? resource : "file:///" + resource;
|
||||
}
|
||||
|
||||
function rezEntity(resource, entityType) {
|
||||
function rezEntity(resource, entityType, resourceObjectId) {
|
||||
print("!!!! tester_rezClicked");
|
||||
sendToScript({
|
||||
method: 'tester_rezClicked',
|
||||
itemHref: toUrl(resource),
|
||||
itemType: entityType});
|
||||
itemType: entityType,
|
||||
itemId: resourceObjectId });
|
||||
}
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 12
|
||||
anchors.bottomMargin: 40
|
||||
anchors.rightMargin: 12
|
||||
model: resourceListModel
|
||||
spacing: 5
|
||||
interactive: false
|
||||
Component.onCompleted: startDate = new Date()
|
||||
|
||||
delegate: RowLayout {
|
||||
ColumnLayout {
|
||||
id: rootColumn
|
||||
spacing: 30
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: rootHeader
|
||||
text: "Marketplace Item Tester"
|
||||
height: 40
|
||||
width: paintedWidth
|
||||
size: 22
|
||||
color: hifi.colors.black
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
anchors.left: parent.left
|
||||
width: parent.width
|
||||
spacing: 5
|
||||
anchors.leftMargin: 12
|
||||
}
|
||||
|
||||
property var actions: {
|
||||
"forward": function(resource, assetType){
|
||||
switch(assetType) {
|
||||
case "application":
|
||||
Commerce.openApp(resource);
|
||||
break;
|
||||
case "avatar":
|
||||
MyAvatar.useFullAvatarURL(resource);
|
||||
break;
|
||||
case "content set":
|
||||
urlHandler.handleUrl("hifi://localhost/0,0,0");
|
||||
Commerce.replaceContentSet(toUrl(resource), "");
|
||||
break;
|
||||
case "entity":
|
||||
case "wearable":
|
||||
rezEntity(resource, assetType);
|
||||
break;
|
||||
default:
|
||||
print("Marketplace item tester unsupported assetType " + assetType);
|
||||
}
|
||||
},
|
||||
"trash": function(resource, assetType){
|
||||
if ("application" === assetType) {
|
||||
Commerce.uninstallApp(resource);
|
||||
}
|
||||
sendToScript({
|
||||
method: "tester_deleteResourceObject",
|
||||
objectId: resourceListModel.get(index).id});
|
||||
resourceListModel.remove(index);
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
height: root.height - 100
|
||||
width: root.width
|
||||
anchors.left: parent.left
|
||||
|
||||
Column {
|
||||
Layout.preferredWidth: root.width * .6
|
||||
spacing: 5
|
||||
Text {
|
||||
text: {
|
||||
var match = resource.match(/\/([^/]*)$/);
|
||||
return match ? match[1] : resource;
|
||||
}
|
||||
font.pointSize: 12
|
||||
horizontalAlignment: Text.AlignBottom
|
||||
}
|
||||
Text {
|
||||
text: resource
|
||||
font.pointSize: 8
|
||||
width: root.width * .6
|
||||
horizontalAlignment: Text.AlignBottom
|
||||
wrapMode: Text.WrapAnywhere
|
||||
}
|
||||
}
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 12
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: 20
|
||||
anchors.leftMargin: 12
|
||||
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn
|
||||
|
||||
ComboBox {
|
||||
id: comboBox
|
||||
frameVisible: false
|
||||
|
||||
Layout.preferredWidth: root.width * .2
|
||||
contentItem: ListView {
|
||||
spacing: 20
|
||||
height: 200
|
||||
model: resourceListModel
|
||||
interactive: false
|
||||
|
||||
model: [
|
||||
"application",
|
||||
"avatar",
|
||||
"content set",
|
||||
"entity",
|
||||
"wearable",
|
||||
"unknown"
|
||||
]
|
||||
delegate: Column {
|
||||
spacing: 8
|
||||
|
||||
currentIndex: (("entity or wearable" === assetType) ?
|
||||
model.indexOf("unknown") : model.indexOf(assetType))
|
||||
RowLayout {
|
||||
id: listRow
|
||||
width: scrollView.width - 20
|
||||
anchors.rightMargin: scrollView.rightMargin
|
||||
spacing: 5
|
||||
|
||||
Component.onCompleted: {
|
||||
onCurrentIndexChanged.connect(function() {
|
||||
assetType = model[currentIndex];
|
||||
sendToScript({
|
||||
method: "tester_updateResourceObjectAssetType",
|
||||
objectId: resourceListModel.get(index)["id"],
|
||||
assetType: assetType });
|
||||
});
|
||||
}
|
||||
}
|
||||
property var actions: {
|
||||
"forward": function(resource, assetType, resourceObjectId){
|
||||
switch(assetType) {
|
||||
case "application":
|
||||
Commerce.openApp(resource);
|
||||
break;
|
||||
case "avatar":
|
||||
MyAvatar.useFullAvatarURL(resource);
|
||||
break;
|
||||
case "content set":
|
||||
urlHandler.handleUrl("hifi://localhost/0,0,0");
|
||||
Commerce.replaceContentSet(toUrl(resource), "");
|
||||
break;
|
||||
case "entity":
|
||||
case "wearable":
|
||||
rezEntity(resource, assetType, resourceObjectId);
|
||||
break;
|
||||
default:
|
||||
print("Marketplace item tester unsupported assetType " + assetType);
|
||||
}
|
||||
},
|
||||
"trash": function(resource, assetType){
|
||||
if ("application" === assetType) {
|
||||
Commerce.uninstallApp(resource);
|
||||
}
|
||||
sendToScript({
|
||||
method: "tester_deleteResourceObject",
|
||||
objectId: resourceListModel.get(index).id});
|
||||
resourceListModel.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: [ "forward", "trash" ]
|
||||
Column {
|
||||
Layout.preferredWidth: scrollView.width * .6
|
||||
spacing: 5
|
||||
Text {
|
||||
width: listRow.width * .6
|
||||
text: {
|
||||
var match = resource.match(/\/([^/]*)$/);
|
||||
return match ? match[1] : resource;
|
||||
}
|
||||
font.pointSize: 12
|
||||
horizontalAlignment: Text.AlignBottom
|
||||
wrapMode: Text.WrapAnywhere
|
||||
}
|
||||
Text {
|
||||
width: listRow.width * .6
|
||||
text: resource
|
||||
font.pointSize: 8
|
||||
horizontalAlignment: Text.AlignBottom
|
||||
wrapMode: Text.WrapAnywhere
|
||||
}
|
||||
}
|
||||
|
||||
HifiStylesUit.HiFiGlyphs {
|
||||
property var glyphs: {
|
||||
"application": hifi.glyphs.install,
|
||||
"avatar": hifi.glyphs.avatar,
|
||||
"content set": hifi.glyphs.globe,
|
||||
"entity": hifi.glyphs.wand,
|
||||
"trash": hifi.glyphs.trash,
|
||||
"unknown": hifi.glyphs.circleSlash,
|
||||
"wearable": hifi.glyphs.hat,
|
||||
}
|
||||
text: (("trash" === modelData) ?
|
||||
glyphs.trash :
|
||||
glyphs[comboBox.model[comboBox.currentIndex]])
|
||||
size: ("trash" === modelData) ? 22 : 30
|
||||
color: hifi.colors.black
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
actions[modelData](resource, comboBox.currentText);
|
||||
ComboBox {
|
||||
id: comboBox
|
||||
|
||||
Layout.preferredWidth: listRow.width * .2
|
||||
|
||||
model: [
|
||||
"application",
|
||||
"avatar",
|
||||
"content set",
|
||||
"entity",
|
||||
"wearable",
|
||||
"unknown"
|
||||
]
|
||||
|
||||
currentIndex: (("entity or wearable" === assetType) ?
|
||||
model.indexOf("unknown") : model.indexOf(assetType))
|
||||
|
||||
Component.onCompleted: {
|
||||
onCurrentIndexChanged.connect(function() {
|
||||
assetType = model[currentIndex];
|
||||
sendToScript({
|
||||
method: "tester_updateResourceObjectAssetType",
|
||||
objectId: resourceListModel.get(index)["resourceObjectId"],
|
||||
assetType: assetType });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: [ "forward", "trash" ]
|
||||
|
||||
HifiStylesUit.HiFiGlyphs {
|
||||
property var glyphs: {
|
||||
"application": hifi.glyphs.install,
|
||||
"avatar": hifi.glyphs.avatar,
|
||||
"content set": hifi.glyphs.globe,
|
||||
"entity": hifi.glyphs.wand,
|
||||
"trash": hifi.glyphs.trash,
|
||||
"unknown": hifi.glyphs.circleSlash,
|
||||
"wearable": hifi.glyphs.hat,
|
||||
}
|
||||
text: (("trash" === modelData) ?
|
||||
glyphs.trash :
|
||||
glyphs[comboBox.model[comboBox.currentIndex]])
|
||||
size: ("trash" === modelData) ? 22 : 30
|
||||
color: hifi.colors.black
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
listRow.actions[modelData](resource, comboBox.currentText, resourceObjectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: detailsContainer
|
||||
|
||||
width: scrollView.width - 20
|
||||
height: resourceDetails.isOpen ? 300 : 20
|
||||
anchors.left: parent.left
|
||||
|
||||
HifiStylesUit.HiFiGlyphs {
|
||||
id: detailsToggle
|
||||
anchors.top: parent.top
|
||||
text: resourceDetails.isOpen ? hifi.glyphs.minimize : hifi.glyphs.maximize
|
||||
color: hifi.colors.black
|
||||
size: 22
|
||||
verticalAlignment: Text.AlignBottom
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: resourceDetails.isOpen = !resourceDetails.isOpen
|
||||
}
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: resourceDetails
|
||||
|
||||
property var isOpen: false
|
||||
|
||||
width: detailsContainer.width - 20
|
||||
height: detailsContainer.height
|
||||
anchors.top: parent.top
|
||||
anchors.left: detailsToggle.left
|
||||
anchors.leftMargin: 20
|
||||
verticalScrollBarPolicy: isOpen ? Qt.ScrollBarAsNeeded : Qt.ScrollBarAlwaysOff
|
||||
frameVisible: isOpen
|
||||
readOnly: true
|
||||
|
||||
text: {
|
||||
if (isOpen) {
|
||||
return resourceAccessEventText
|
||||
} else {
|
||||
return (resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..."
|
||||
}
|
||||
}
|
||||
font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal })
|
||||
wrapMode: TextEdit.NoWrap
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: listRow.width
|
||||
height: 1
|
||||
color: hifi.colors.black
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
headerPositioning: ListView.OverlayHeader
|
||||
header: HifiStylesUit.RalewayRegular {
|
||||
id: rootHeader
|
||||
text: "Marketplace Item Tester"
|
||||
height: 80
|
||||
width: paintedWidth
|
||||
size: 22
|
||||
color: hifi.colors.black
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
}
|
||||
|
||||
footerPositioning: ListView.OverlayFooter
|
||||
footer: Row {
|
||||
Row {
|
||||
id: rootActions
|
||||
spacing: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.width / 6 - 10
|
||||
anchors.bottomMargin: 40
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
property string currentAction
|
||||
property var actions: {
|
||||
|
@ -257,6 +365,7 @@ Rectangle {
|
|||
// Alas, there is nothing we can do about that so charge
|
||||
// ahead as though we are sure the present signal is one
|
||||
// we expect.
|
||||
print("!!!! resource selected");
|
||||
switch(currentAction) {
|
||||
case "load file":
|
||||
Window.browseChanged.disconnect(onResourceSelected);
|
||||
|
@ -266,8 +375,11 @@ Rectangle {
|
|||
break;
|
||||
}
|
||||
if (resource) {
|
||||
print("!!!! building resource object");
|
||||
var resourceObj = buildResourceObj(resource);
|
||||
print("!!!! installing resource object");
|
||||
installResourceObj(resourceObj);
|
||||
print("!!!! notifying script of resource object");
|
||||
sendToScript({
|
||||
method: 'tester_newResourceObject',
|
||||
resourceObject: resourceObj });
|
||||
|
@ -282,7 +394,7 @@ Rectangle {
|
|||
text: modelData
|
||||
width: root.width / 3
|
||||
height: 40
|
||||
onClicked: actions[text]()
|
||||
onClicked: rootActions.actions[text]()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,6 +170,7 @@
|
|||
#include "ModelPackager.h"
|
||||
#include "scripting/Audio.h"
|
||||
#include "networking/CloseEventSender.h"
|
||||
#include "QUrlAncestry.h"
|
||||
#include "scripting/TestScriptingInterface.h"
|
||||
#include "scripting/AssetMappingsScriptingInterface.h"
|
||||
#include "scripting/ClipboardScriptingInterface.h"
|
||||
|
@ -226,6 +227,7 @@
|
|||
#include "commerce/Ledger.h"
|
||||
#include "commerce/Wallet.h"
|
||||
#include "commerce/QmlCommerce.h"
|
||||
#include "ResourceRequestObserver.h"
|
||||
|
||||
#include "webbrowser/WebBrowserSuggestionsEngine.h"
|
||||
#include <DesktopPreviewProvider.h>
|
||||
|
@ -945,8 +947,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<Ledger>();
|
||||
DependencyManager::set<Wallet>();
|
||||
DependencyManager::set<WalletScriptingInterface>();
|
||||
|
||||
DependencyManager::set<FadeEffect>();
|
||||
DependencyManager::set<ResourceRequestObserver>();
|
||||
|
||||
return previousSessionCrashed;
|
||||
}
|
||||
|
@ -1781,7 +1783,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
updateHeartbeat();
|
||||
QTimer* settingsTimer = new QTimer();
|
||||
moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{
|
||||
// This needs to run on the settings thread, so we need to pass the `settingsTimer` as the
|
||||
// This needs to run on the settings thread, so we need to pass the `settingsTimer` as the
|
||||
// receiver object, otherwise it will run on the application thread and trigger a warning
|
||||
// about trying to kill the timer on the main thread.
|
||||
connect(qApp, &Application::beforeAboutToQuit, settingsTimer, [this, settingsTimer]{
|
||||
|
@ -3129,6 +3131,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
|
||||
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance());
|
||||
surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
|
||||
|
||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
|
||||
|
@ -5021,12 +5024,11 @@ void Application::saveSettings() const {
|
|||
PluginManager::getInstance()->saveSettings();
|
||||
}
|
||||
|
||||
bool Application::importEntities(const QString& urlOrFilename) {
|
||||
bool Application::importEntities(const QString& urlOrFilename, const bool isObservable, const qint64 callerId) {
|
||||
bool success = false;
|
||||
_entityClipboard->withWriteLock([&] {
|
||||
_entityClipboard->eraseAllOctreeElements();
|
||||
|
||||
success = _entityClipboard->readFromURL(urlOrFilename);
|
||||
success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId, QUrlAncestry());
|
||||
if (success) {
|
||||
_entityClipboard->reaverageOctreeElements();
|
||||
}
|
||||
|
@ -6810,6 +6812,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGlobalObject("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance());
|
||||
scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
|
||||
|
||||
qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);
|
||||
|
||||
|
@ -7196,7 +7199,8 @@ void Application::addAssetToWorldFromURL(QString url) {
|
|||
|
||||
addAssetToWorldInfo(filename, "Downloading model file " + filename + ".");
|
||||
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, QUrl(url));
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
nullptr, QUrl(url), true, -1, "Application::addAssetToWorldFromURL");
|
||||
connect(request, &ResourceRequest::finished, this, &Application::addAssetToWorldFromURLRequestFinished);
|
||||
request->send();
|
||||
}
|
||||
|
|
|
@ -340,7 +340,7 @@ public slots:
|
|||
QVector<EntityItemID> pasteEntities(float x, float y, float z);
|
||||
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
|
||||
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
|
||||
bool importEntities(const QString& url);
|
||||
bool importEntities(const QString& url, const bool isObservable = true, const qint64 callerId = -1);
|
||||
void updateThreadPoolCount() const;
|
||||
void updateSystemTabletMode();
|
||||
void goToErrorDomainURL(QUrl errorDomainURL);
|
||||
|
|
|
@ -53,7 +53,8 @@ void ATPAssetMigrator::loadEntityServerFile() {
|
|||
|
||||
auto migrateResources = [=](QUrl migrationURL, QJsonValueRef jsonValue, bool isModelURL) {
|
||||
auto request =
|
||||
DependencyManager::get<ResourceManager>()->createResourceRequest(this, migrationURL);
|
||||
DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
this, migrationURL, true, -1, "ATPAssetMigrator::loadEntityServerFile");
|
||||
|
||||
if (request) {
|
||||
qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration";
|
||||
|
@ -202,7 +203,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
|
|||
void ATPAssetMigrator::migrateResource(ResourceRequest* request) {
|
||||
// use an asset client to upload the asset
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
|
||||
|
||||
auto upload = assetClient->createUpload(request->getData());
|
||||
|
||||
// add this URL to our hash of AssetUpload to original URL
|
||||
|
@ -242,7 +243,7 @@ void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& h
|
|||
}
|
||||
|
||||
checkIfFinished();
|
||||
|
||||
|
||||
upload->deleteLater();
|
||||
}
|
||||
|
||||
|
@ -298,24 +299,24 @@ void ATPAssetMigrator::checkIfFinished() {
|
|||
bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) {
|
||||
static bool hasAskedForCompleteMigration { false };
|
||||
static bool wantsCompleteMigration { false };
|
||||
|
||||
|
||||
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"\
|
||||
"Select \"Yes\" to upload all discovered assets to the current asset-server immediately.\n"\
|
||||
"Select \"No\" to be prompted for each discovered asset."
|
||||
};
|
||||
|
||||
|
||||
auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE, COMPLETE_MIGRATION_TEXT,
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
|
||||
|
||||
if (button == QMessageBox::Yes) {
|
||||
wantsCompleteMigration = true;
|
||||
}
|
||||
|
||||
|
||||
hasAskedForCompleteMigration = true;
|
||||
}
|
||||
|
||||
|
||||
if (wantsCompleteMigration) {
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -325,7 +325,8 @@ bool QmlCommerce::installApp(const QString& itemHref) {
|
|||
|
||||
QUrl appHref(itemHref);
|
||||
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, appHref);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
this, appHref, true, -1, "QmlCommerce::installApp");
|
||||
|
||||
if (!request) {
|
||||
qCDebug(commerce) << "Couldn't create resource request for app.";
|
||||
|
|
|
@ -46,11 +46,17 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float
|
|||
return retVal;
|
||||
}
|
||||
|
||||
bool ClipboardScriptingInterface::importEntities(const QString& filename) {
|
||||
bool ClipboardScriptingInterface::importEntities(
|
||||
const QString& filename,
|
||||
const bool isObservable,
|
||||
const qint64 callerId
|
||||
) {
|
||||
bool retVal;
|
||||
BLOCKING_INVOKE_METHOD(qApp, "importEntities",
|
||||
Q_RETURN_ARG(bool, retVal),
|
||||
Q_ARG(const QString&, filename));
|
||||
Q_ARG(const QString&, filename),
|
||||
Q_ARG(const bool, isObservable),
|
||||
Q_ARG(const qint64, callerId));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,9 +50,11 @@ public:
|
|||
* You can generate a JSON file using {@link Clipboard.exportEntities}.
|
||||
* @function Clipboard.importEntities
|
||||
* @param {string} filename Path and name of file to import.
|
||||
* @param {boolean} does the ResourceRequestObserver observe this request?
|
||||
* @param {number} optional internal id of object causing this import.
|
||||
* @returns {boolean} <code>true</code> if the import was successful, otherwise <code>false</code>.
|
||||
*/
|
||||
Q_INVOKABLE bool importEntities(const QString& filename);
|
||||
Q_INVOKABLE bool importEntities(const QString& filename, const bool isObservable = true, const qint64 callerId = -1);
|
||||
|
||||
/**jsdoc
|
||||
* Export the entities specified to a JSON file.
|
||||
|
@ -62,7 +64,7 @@ public:
|
|||
* @returns {boolean} <code>true</code> if the export was successful, otherwise <code>false</code>.
|
||||
*/
|
||||
Q_INVOKABLE bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs);
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* Export the entities with centers within a cube to a JSON file.
|
||||
* @function Clipboard.exportEntities
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
#include "raypick/PointerScriptingInterface.h"
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
#include "AboutUtil.h"
|
||||
#include "ResourceRequestObserver.h"
|
||||
|
||||
|
||||
static int MAX_WINDOW_SIZE = 4096;
|
||||
static const float METERS_TO_INCHES = 39.3701f;
|
||||
|
@ -269,6 +271,7 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) {
|
|||
_webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
|
||||
|
||||
// Override min fps for tablet UI, for silky smooth scrolling
|
||||
setMaxFPS(90);
|
||||
|
@ -536,7 +539,7 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
* <code>start</code>.
|
||||
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
|
||||
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
|
||||
|
@ -561,7 +564,7 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* @property {string} url - The URL of the Web page to display.
|
||||
* @property {string} scriptURL="" - The URL of a JavaScript file to inject into the Web page.
|
||||
* @property {number} dpi=30 - The dots per inch to display the Web page at, on the overlay.
|
||||
* @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms:
|
||||
* @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms:
|
||||
* <code>scale</code>, <code>size</code>.
|
||||
* @property {number} maxFPS=10 - The maximum update rate for the Web overlay content, in frames/second.
|
||||
* @property {boolean} showKeyboardFocusHighlight=true - If <code>true</code>, the Web overlay is highlighted when it has
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "AvatarLogging.h"
|
||||
#include "AvatarTraits.h"
|
||||
#include "ClientTraitsHandler.h"
|
||||
#include "ResourceRequestObserver.h"
|
||||
|
||||
//#define WANT_DEBUG
|
||||
|
||||
|
@ -379,7 +380,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
} else {
|
||||
AVATAR_MEMCPY(_globalPosition);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int numBytes = destinationBuffer - startSection;
|
||||
|
||||
|
@ -647,7 +648,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
if (!data.translationIsDefaultPose) {
|
||||
if (sendAll || last.translationIsDefaultPose || (!cullSmallChanges && last.translation != data.translation)
|
||||
|| (cullSmallChanges && glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation)) {
|
||||
|
||||
|
||||
validity |= (1 << validityBit);
|
||||
#ifdef WANT_DEBUG
|
||||
translationSentCount++;
|
||||
|
@ -1054,7 +1055,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
auto newHasProceduralEyeFaceMovement = oneAtBit16(bitItems, PROCEDURAL_EYE_FACE_MOVEMENT);
|
||||
auto newHasProceduralBlinkFaceMovement = oneAtBit16(bitItems, PROCEDURAL_BLINK_FACE_MOVEMENT);
|
||||
|
||||
|
||||
|
||||
bool keyStateChanged = (_keyState != newKeyState);
|
||||
bool handStateChanged = (_handState != newHandState);
|
||||
bool faceStateChanged = (_headData->_isFaceTrackerConnected != newFaceTrackerConnected);
|
||||
|
@ -1526,7 +1527,7 @@ glm::vec3 AvatarData::getJointTranslation(int index) const {
|
|||
}
|
||||
|
||||
glm::vec3 AvatarData::getJointTranslation(const QString& name) const {
|
||||
// Can't do this, because the lock needs to cover the entire set of logic. In theory, the joints could change
|
||||
// Can't do this, because the lock needs to cover the entire set of logic. In theory, the joints could change
|
||||
// on another thread in between the call to getJointIndex and getJointTranslation
|
||||
// return getJointTranslation(getJointIndex(name));
|
||||
return readLockWithNamedJointIndex<glm::vec3>(name, [this](int index) {
|
||||
|
@ -1607,7 +1608,7 @@ bool AvatarData::isJointDataValid(const QString& name) const {
|
|||
// return isJointDataValid(getJointIndex(name));
|
||||
|
||||
return readLockWithNamedJointIndex<bool>(name, false, [&](int index) {
|
||||
// This is technically superfluous.... the lambda is only called if index is a valid
|
||||
// This is technically superfluous.... the lambda is only called if index is a valid
|
||||
// offset for _jointData. Nevertheless, it would be confusing to leave the lamdba as
|
||||
// `return true`
|
||||
return index < _jointData.size();
|
||||
|
@ -1826,7 +1827,7 @@ qint64 AvatarData::packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice
|
|||
if (traitVersion > AvatarTraits::DEFAULT_TRAIT_VERSION) {
|
||||
bytesWritten += destination.writePrimitive(traitVersion);
|
||||
}
|
||||
|
||||
|
||||
AvatarTraits::TraitWireSize encodedURLSize = encodedSkeletonURL.size();
|
||||
bytesWritten += destination.writePrimitive(encodedURLSize);
|
||||
|
||||
|
@ -1935,7 +1936,7 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
if (expanded == _skeletonModelURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_skeletonModelURL = expanded;
|
||||
qCDebug(avatars) << "Changing skeleton model for avatar" << getSessionUUID() << "to" << _skeletonModelURL.toString();
|
||||
|
||||
|
@ -2161,11 +2162,21 @@ void AvatarData::updateJointMappings() {
|
|||
}
|
||||
|
||||
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
|
||||
////
|
||||
// TODO: Should we rely upon HTTPResourceRequest instead?
|
||||
// HTTPResourceRequest::doSend() covers all of the following and
|
||||
// then some. It doesn't cover the connect() call, so we may
|
||||
// want to add a HTTPResourceRequest::doSend() method that does
|
||||
// connects.
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
DependencyManager::get<ResourceRequestObserver>()->update(
|
||||
_skeletonModelURL, -1, "AvatarData::updateJointMappings");
|
||||
QNetworkReply* networkReply = networkAccessManager.get(networkRequest);
|
||||
//
|
||||
////
|
||||
connect(networkReply, &QNetworkReply::finished, this, &AvatarData::setJointMappingsFromNetworkReply);
|
||||
}
|
||||
}
|
||||
|
@ -2391,7 +2402,7 @@ QJsonObject AvatarData::toJson() const {
|
|||
for (auto entityID : _avatarEntityData.keys()) {
|
||||
QVariantMap entityData;
|
||||
QUuid newId = _avatarEntityForRecording.size() == _avatarEntityData.size() ? _avatarEntityForRecording.values()[entityCount++] : entityID;
|
||||
entityData.insert("id", newId);
|
||||
entityData.insert("id", newId);
|
||||
entityData.insert("properties", _avatarEntityData.value(entityID).toBase64());
|
||||
avatarEntityJson.push_back(QVariant(entityData).toJsonObject());
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ QList<EntityItemID> EntityEditFilters::getZonesByPosition(glm::vec3& position) {
|
|||
for (auto id : zoneIDs) {
|
||||
if (!id.isInvalidID()) {
|
||||
// for now, look it up in the tree (soon we need to cache or similar?)
|
||||
EntityItemPointer itemPtr = _tree->findEntityByEntityItemID(id);
|
||||
EntityItemPointer itemPtr = _tree->findEntityByEntityItemID(id);
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(itemPtr);
|
||||
if (!zone) {
|
||||
// TODO: maybe remove later?
|
||||
|
@ -33,7 +33,7 @@ QList<EntityItemID> EntityEditFilters::getZonesByPosition(glm::vec3& position) {
|
|||
zones.append(id);
|
||||
}
|
||||
} else {
|
||||
// the null id is the global filter we put in the domain server's
|
||||
// the null id is the global filter we put in the domain server's
|
||||
// advanced entity server settings
|
||||
zones.append(id);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ QList<EntityItemID> EntityEditFilters::getZonesByPosition(glm::vec3& position) {
|
|||
|
||||
bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut,
|
||||
bool& wasChanged, EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) {
|
||||
|
||||
|
||||
// get the ids of all the zones (plus the global entity edit filter) that the position
|
||||
// lies within
|
||||
auto zoneIDs = getZonesByPosition(position);
|
||||
|
@ -51,12 +51,12 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper
|
|||
if (!itemID.isInvalidID() && id == itemID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the filter pair, etc...
|
||||
|
||||
// get the filter pair, etc...
|
||||
_lock.lockForRead();
|
||||
FilterData filterData = _filterDataMap.value(id);
|
||||
_lock.unlock();
|
||||
|
||||
|
||||
if (filterData.valid()) {
|
||||
if (filterData.rejectAll) {
|
||||
return false;
|
||||
|
@ -153,13 +153,13 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper
|
|||
// otherwise, assume it wants to pass all properties
|
||||
propertiesOut = propertiesIn;
|
||||
wasChanged = false;
|
||||
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we made it here,
|
||||
// if we made it here,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -175,23 +175,23 @@ void EntityEditFilters::removeFilter(EntityItemID entityID) {
|
|||
void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) {
|
||||
|
||||
QUrl scriptURL(filterURL);
|
||||
|
||||
// setting it to an empty string is same as removing
|
||||
|
||||
// setting it to an empty string is same as removing
|
||||
if (filterURL.size() == 0) {
|
||||
removeFilter(entityID);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// The following should be abstracted out for use in Agent.cpp (and maybe later AvatarMixer.cpp)
|
||||
if (scriptURL.scheme().isEmpty() || (scriptURL.scheme() == URL_SCHEME_FILE)) {
|
||||
qWarning() << "Cannot load script from local filesystem, because assignment may be on a different computer.";
|
||||
scriptRequestFinished(entityID);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// first remove any existing info for this entity
|
||||
removeFilter(entityID);
|
||||
|
||||
|
||||
// reject all edits until we load the script
|
||||
FilterData filterData;
|
||||
filterData.rejectAll = true;
|
||||
|
@ -199,8 +199,9 @@ void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) {
|
|||
_lock.lockForWrite();
|
||||
_filterDataMap.insert(entityID, filterData);
|
||||
_lock.unlock();
|
||||
|
||||
auto scriptRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, scriptURL);
|
||||
|
||||
auto scriptRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
this, scriptURL, true, -1, "EntityEditFilters::addFilter");
|
||||
if (!scriptRequest) {
|
||||
qWarning() << "Could not create ResourceRequest for Entity Edit filter script at" << scriptURL.toString();
|
||||
scriptRequestFinished(entityID);
|
||||
|
@ -264,7 +265,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) {
|
|||
FilterData filterData;
|
||||
filterData.engine = engine;
|
||||
filterData.rejectAll = false;
|
||||
|
||||
|
||||
// define the uncaughtException function
|
||||
QScriptEngine& engineRef = *engine;
|
||||
filterData.uncaughtExceptions = [&engineRef, urlString]() { return hadUncaughtExceptions(engineRef, urlString); };
|
||||
|
@ -368,11 +369,11 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) {
|
|||
_lock.unlock();
|
||||
|
||||
qDebug() << "script request filter processed for entity id " << entityID;
|
||||
|
||||
|
||||
emit filterAdded(entityID, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (scriptRequest) {
|
||||
const QString urlString = scriptRequest->getUrl().toString();
|
||||
qCritical() << "Failed to download script at" << urlString;
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
#include "LogHandler.h"
|
||||
#include "EntityEditFilters.h"
|
||||
#include "EntityDynamicFactoryInterface.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50;
|
||||
const float EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME = 60 * 60; // 1 hour
|
||||
|
@ -98,7 +100,7 @@ EntityTree::~EntityTree() {
|
|||
eraseAllOctreeElements(false);
|
||||
}
|
||||
|
||||
void EntityTree::setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist) {
|
||||
void EntityTree::setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist) {
|
||||
_entityScriptSourceWhitelist = entityScriptSourceWhitelist.split(',', QString::SkipEmptyParts);
|
||||
}
|
||||
|
||||
|
@ -860,7 +862,7 @@ float findRayIntersectionSortingOp(const OctreeElementPointer& element, void* ex
|
|||
|
||||
EntityItemID EntityTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
QVector<EntityItemID> entityIdsToInclude, QVector<EntityItemID> entityIdsToDiscard,
|
||||
bool visibleOnly, bool collidableOnly, bool precisionPicking,
|
||||
bool visibleOnly, bool collidableOnly, bool precisionPicking,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
Octree::lockType lockType, bool* accurateResult) {
|
||||
|
@ -1351,7 +1353,7 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity
|
|||
key = sent.second;
|
||||
}
|
||||
|
||||
QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n";
|
||||
QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n";
|
||||
QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256);
|
||||
bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8()));
|
||||
|
||||
|
@ -1795,7 +1797,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
|
|||
if (newEntity) {
|
||||
newEntity->markAsChangedOnServer();
|
||||
notifyNewlyCreatedEntity(*newEntity, senderNode);
|
||||
|
||||
|
||||
startLogging = usecTimestampNow();
|
||||
if (wantEditLogging()) {
|
||||
qCDebug(entities) << "User [" << senderNode->getUUID() << "] added entity. ID:"
|
||||
|
@ -1820,7 +1822,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
|
|||
}
|
||||
} else {
|
||||
HIFI_FCDEBUG(entities(), "Edit failed. [" << message.getType() <<"] " <<
|
||||
"entity id:" << entityItemID <<
|
||||
"entity id:" << entityItemID <<
|
||||
"existingEntity pointer:" << existingEntity.get());
|
||||
}
|
||||
}
|
||||
|
@ -2041,7 +2043,7 @@ bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) {
|
|||
if (hasSomethingNewer) {
|
||||
int elapsed = usecTimestampNow() - considerEntitiesSince;
|
||||
int difference = considerEntitiesSince - sinceTime;
|
||||
qCDebug(entities) << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime
|
||||
qCDebug(entities) << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime
|
||||
<< "considerEntitiesSince:" << considerEntitiesSince << "elapsed:" << elapsed << "difference:" << difference;
|
||||
}
|
||||
#endif
|
||||
|
@ -2493,7 +2495,7 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EntityTree::readFromMap(QVariantMap& map) {
|
||||
bool EntityTree::readFromMap(QVariantMap& map, const QUrlAncestry& ancestry) {
|
||||
// These are needed to deal with older content (before adding inheritance modes)
|
||||
int contentVersion = map["Version"].toInt();
|
||||
bool needsConversion = (contentVersion < (int)EntityVersion::ZoneLightInheritModes);
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "EntityTreeElement.h"
|
||||
#include "DeleteEntityOperator.h"
|
||||
#include "MovingEntitiesOperator.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
class EntityTree;
|
||||
using EntityTreePointer = std::shared_ptr<EntityTree>;
|
||||
|
@ -94,7 +96,7 @@ public:
|
|||
|
||||
virtual EntityItemID findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
QVector<EntityItemID> entityIdsToInclude, QVector<EntityItemID> entityIdsToDiscard,
|
||||
bool visibleOnly, bool collidableOnly, bool precisionPicking,
|
||||
bool visibleOnly, bool collidableOnly, bool precisionPicking,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
|
||||
|
@ -170,7 +172,7 @@ public:
|
|||
void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
||||
void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
||||
|
||||
bool hasAnyDeletedEntities() const {
|
||||
bool hasAnyDeletedEntities() const {
|
||||
QReadLocker locker(&_recentlyDeletedEntitiesLock);
|
||||
return _recentlyDeletedEntityItemIDs.size() > 0;
|
||||
}
|
||||
|
@ -178,7 +180,7 @@ public:
|
|||
bool hasEntitiesDeletedSince(quint64 sinceTime);
|
||||
static quint64 getAdjustedConsiderSince(quint64 sinceTime);
|
||||
|
||||
QMultiMap<quint64, QUuid> getRecentlyDeletedEntityIDs() const {
|
||||
QMultiMap<quint64, QUuid> getRecentlyDeletedEntityIDs() const {
|
||||
QReadLocker locker(&_recentlyDeletedEntitiesLock);
|
||||
return _recentlyDeletedEntityItemIDs;
|
||||
}
|
||||
|
@ -223,7 +225,7 @@ public:
|
|||
|
||||
virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues,
|
||||
bool skipThoseWithBadParents) override;
|
||||
virtual bool readFromMap(QVariantMap& entityDescription) override;
|
||||
virtual bool readFromMap(QVariantMap& entityDescription, const QUrlAncestry& ancestry = {}) override;
|
||||
|
||||
glm::vec3 getContentsDimensions();
|
||||
float getContentsLargestDimension();
|
||||
|
|
|
@ -40,7 +40,7 @@ GLTFReader::GLTFReader() {
|
|||
|
||||
}
|
||||
|
||||
bool GLTFReader::getStringVal(const QJsonObject& object, const QString& fieldname,
|
||||
bool GLTFReader::getStringVal(const QJsonObject& object, const QString& fieldname,
|
||||
QString& value, QMap<QString, bool>& defined) {
|
||||
bool _defined = (object.contains(fieldname) && object[fieldname].isString());
|
||||
if (_defined) {
|
||||
|
@ -60,7 +60,7 @@ bool GLTFReader::getBoolVal(const QJsonObject& object, const QString& fieldname,
|
|||
return _defined;
|
||||
}
|
||||
|
||||
bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname,
|
||||
bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname,
|
||||
int& value, QMap<QString, bool>& defined) {
|
||||
bool _defined = (object.contains(fieldname) && !object[fieldname].isNull());
|
||||
if (_defined) {
|
||||
|
@ -70,7 +70,7 @@ bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname,
|
|||
return _defined;
|
||||
}
|
||||
|
||||
bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldname,
|
||||
bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldname,
|
||||
double& value, QMap<QString, bool>& defined) {
|
||||
bool _defined = (object.contains(fieldname) && object[fieldname].isDouble());
|
||||
if (_defined) {
|
||||
|
@ -79,7 +79,7 @@ bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldnam
|
|||
defined.insert(fieldname, _defined);
|
||||
return _defined;
|
||||
}
|
||||
bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldname,
|
||||
bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldname,
|
||||
QJsonObject& value, QMap<QString, bool>& defined) {
|
||||
bool _defined = (object.contains(fieldname) && object[fieldname].isObject());
|
||||
if (_defined) {
|
||||
|
@ -89,7 +89,7 @@ bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldnam
|
|||
return _defined;
|
||||
}
|
||||
|
||||
bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldname,
|
||||
bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldname,
|
||||
QVector<int>& values, QMap<QString, bool>& defined) {
|
||||
bool _defined = (object.contains(fieldname) && object[fieldname].isArray());
|
||||
if (_defined) {
|
||||
|
@ -104,7 +104,7 @@ bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldn
|
|||
return _defined;
|
||||
}
|
||||
|
||||
bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fieldname,
|
||||
bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fieldname,
|
||||
QVector<double>& values, QMap<QString, bool>& defined) {
|
||||
bool _defined = (object.contains(fieldname) && object[fieldname].isArray());
|
||||
if (_defined) {
|
||||
|
@ -119,7 +119,7 @@ bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fie
|
|||
return _defined;
|
||||
}
|
||||
|
||||
bool GLTFReader::getObjectArrayVal(const QJsonObject& object, const QString& fieldname,
|
||||
bool GLTFReader::getObjectArrayVal(const QJsonObject& object, const QString& fieldname,
|
||||
QJsonArray& objects, QMap<QString, bool>& defined) {
|
||||
bool _defined = (object.contains(fieldname) && object[fieldname].isArray());
|
||||
if (_defined) {
|
||||
|
@ -229,7 +229,7 @@ bool GLTFReader::setAsset(const QJsonObject& object) {
|
|||
QJsonObject jsAsset;
|
||||
bool isAssetDefined = getObjectVal(object, "asset", jsAsset, _file.defined);
|
||||
if (isAssetDefined) {
|
||||
if (!getStringVal(jsAsset, "version", _file.asset.version,
|
||||
if (!getStringVal(jsAsset, "version", _file.asset.version,
|
||||
_file.asset.defined) || _file.asset.version != "2.0") {
|
||||
return false;
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ bool GLTFReader::setAsset(const QJsonObject& object) {
|
|||
|
||||
bool GLTFReader::addAccessor(const QJsonObject& object) {
|
||||
GLTFAccessor accessor;
|
||||
|
||||
|
||||
getIntVal(object, "bufferView", accessor.bufferView, accessor.defined);
|
||||
getIntVal(object, "byteOffset", accessor.byteOffset, accessor.defined);
|
||||
getIntVal(object, "componentType", accessor.componentType, accessor.defined);
|
||||
|
@ -261,7 +261,7 @@ bool GLTFReader::addAccessor(const QJsonObject& object) {
|
|||
|
||||
bool GLTFReader::addAnimation(const QJsonObject& object) {
|
||||
GLTFAnimation animation;
|
||||
|
||||
|
||||
QJsonArray channels;
|
||||
if (getObjectArrayVal(object, "channels", channels, animation.defined)) {
|
||||
foreach(const QJsonValue & v, channels) {
|
||||
|
@ -272,7 +272,7 @@ bool GLTFReader::addAnimation(const QJsonObject& object) {
|
|||
if (getObjectVal(v.toObject(), "target", jsChannel, channel.defined)) {
|
||||
getIntVal(jsChannel, "node", channel.target.node, channel.target.defined);
|
||||
getIntVal(jsChannel, "path", channel.target.path, channel.target.defined);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ bool GLTFReader::addAnimation(const QJsonObject& object) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_file.animations.push_back(animation);
|
||||
|
||||
return true;
|
||||
|
@ -299,20 +299,20 @@ bool GLTFReader::addAnimation(const QJsonObject& object) {
|
|||
|
||||
bool GLTFReader::addBufferView(const QJsonObject& object) {
|
||||
GLTFBufferView bufferview;
|
||||
|
||||
|
||||
getIntVal(object, "buffer", bufferview.buffer, bufferview.defined);
|
||||
getIntVal(object, "byteLength", bufferview.byteLength, bufferview.defined);
|
||||
getIntVal(object, "byteOffset", bufferview.byteOffset, bufferview.defined);
|
||||
getIntVal(object, "target", bufferview.target, bufferview.defined);
|
||||
|
||||
|
||||
_file.bufferviews.push_back(bufferview);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLTFReader::addBuffer(const QJsonObject& object) {
|
||||
GLTFBuffer buffer;
|
||||
|
||||
|
||||
getIntVal(object, "byteLength", buffer.byteLength, buffer.defined);
|
||||
if (getStringVal(object, "uri", buffer.uri, buffer.defined)) {
|
||||
if (!readBinary(buffer.uri, buffer.blob)) {
|
||||
|
@ -320,13 +320,13 @@ bool GLTFReader::addBuffer(const QJsonObject& object) {
|
|||
}
|
||||
}
|
||||
_file.buffers.push_back(buffer);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLTFReader::addCamera(const QJsonObject& object) {
|
||||
GLTFCamera camera;
|
||||
|
||||
|
||||
QJsonObject jsPerspective;
|
||||
QJsonObject jsOrthographic;
|
||||
QString type;
|
||||
|
@ -346,28 +346,28 @@ bool GLTFReader::addCamera(const QJsonObject& object) {
|
|||
} else if (getStringVal(object, "type", type, camera.defined)) {
|
||||
camera.type = getCameraType(type);
|
||||
}
|
||||
|
||||
|
||||
_file.cameras.push_back(camera);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLTFReader::addImage(const QJsonObject& object) {
|
||||
GLTFImage image;
|
||||
|
||||
|
||||
QString mime;
|
||||
getStringVal(object, "uri", image.uri, image.defined);
|
||||
if (getStringVal(object, "mimeType", mime, image.defined)) {
|
||||
image.mimeType = getImageMimeType(mime);
|
||||
}
|
||||
getIntVal(object, "bufferView", image.bufferView, image.defined);
|
||||
|
||||
|
||||
_file.images.push_back(image);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLTFReader::getIndexFromObject(const QJsonObject& object, const QString& field,
|
||||
bool GLTFReader::getIndexFromObject(const QJsonObject& object, const QString& field,
|
||||
int& outidx, QMap<QString, bool>& defined) {
|
||||
QJsonObject subobject;
|
||||
if (getObjectVal(object, field, subobject, defined)) {
|
||||
|
@ -393,20 +393,20 @@ bool GLTFReader::addMaterial(const QJsonObject& object) {
|
|||
getDoubleVal(object, "alphaCutoff", material.alphaCutoff, material.defined);
|
||||
QJsonObject jsMetallicRoughness;
|
||||
if (getObjectVal(object, "pbrMetallicRoughness", jsMetallicRoughness, material.defined)) {
|
||||
getDoubleArrayVal(jsMetallicRoughness, "baseColorFactor",
|
||||
material.pbrMetallicRoughness.baseColorFactor,
|
||||
getDoubleArrayVal(jsMetallicRoughness, "baseColorFactor",
|
||||
material.pbrMetallicRoughness.baseColorFactor,
|
||||
material.pbrMetallicRoughness.defined);
|
||||
getIndexFromObject(jsMetallicRoughness, "baseColorTexture",
|
||||
material.pbrMetallicRoughness.baseColorTexture,
|
||||
getIndexFromObject(jsMetallicRoughness, "baseColorTexture",
|
||||
material.pbrMetallicRoughness.baseColorTexture,
|
||||
material.pbrMetallicRoughness.defined);
|
||||
getDoubleVal(jsMetallicRoughness, "metallicFactor",
|
||||
material.pbrMetallicRoughness.metallicFactor,
|
||||
getDoubleVal(jsMetallicRoughness, "metallicFactor",
|
||||
material.pbrMetallicRoughness.metallicFactor,
|
||||
material.pbrMetallicRoughness.defined);
|
||||
getDoubleVal(jsMetallicRoughness, "roughnessFactor",
|
||||
material.pbrMetallicRoughness.roughnessFactor,
|
||||
getDoubleVal(jsMetallicRoughness, "roughnessFactor",
|
||||
material.pbrMetallicRoughness.roughnessFactor,
|
||||
material.pbrMetallicRoughness.defined);
|
||||
getIndexFromObject(jsMetallicRoughness, "metallicRoughnessTexture",
|
||||
material.pbrMetallicRoughness.metallicRoughnessTexture,
|
||||
getIndexFromObject(jsMetallicRoughness, "metallicRoughnessTexture",
|
||||
material.pbrMetallicRoughness.metallicRoughnessTexture,
|
||||
material.pbrMetallicRoughness.defined);
|
||||
}
|
||||
_file.materials.push_back(material);
|
||||
|
@ -428,7 +428,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) {
|
|||
getIntVal(jsPrimitive, "mode", primitive.mode, primitive.defined);
|
||||
getIntVal(jsPrimitive, "indices", primitive.indices, primitive.defined);
|
||||
getIntVal(jsPrimitive, "material", primitive.material, primitive.defined);
|
||||
|
||||
|
||||
QJsonObject jsAttributes;
|
||||
if (getObjectVal(jsPrimitive, "attributes", jsAttributes, primitive.defined)) {
|
||||
QStringList attrKeys = jsAttributes.keys();
|
||||
|
@ -455,7 +455,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) {
|
|||
primitive.targets.push_back(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mesh.primitives.push_back(primitive);
|
||||
}
|
||||
}
|
||||
|
@ -469,7 +469,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) {
|
|||
|
||||
bool GLTFReader::addNode(const QJsonObject& object) {
|
||||
GLTFNode node;
|
||||
|
||||
|
||||
getStringVal(object, "name", node.name, node.defined);
|
||||
getIntVal(object, "camera", node.camera, node.defined);
|
||||
getIntVal(object, "mesh", node.mesh, node.defined);
|
||||
|
@ -524,10 +524,10 @@ bool GLTFReader::addSkin(const QJsonObject& object) {
|
|||
}
|
||||
|
||||
bool GLTFReader::addTexture(const QJsonObject& object) {
|
||||
GLTFTexture texture;
|
||||
GLTFTexture texture;
|
||||
getIntVal(object, "sampler", texture.sampler, texture.defined);
|
||||
getIntVal(object, "source", texture.source, texture.defined);
|
||||
|
||||
|
||||
_file.textures.push_back(texture);
|
||||
|
||||
return true;
|
||||
|
@ -535,7 +535,7 @@ bool GLTFReader::addTexture(const QJsonObject& object) {
|
|||
|
||||
bool GLTFReader::parseGLTF(const QByteArray& model) {
|
||||
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
|
||||
|
||||
|
||||
QJsonDocument d = QJsonDocument::fromJson(model);
|
||||
QJsonObject jsFile = d.object();
|
||||
|
||||
|
@ -707,25 +707,25 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
foreach(int child, node.children) nodeDependencies[child].push_back(nodecount);
|
||||
nodecount++;
|
||||
}
|
||||
|
||||
|
||||
nodecount = 0;
|
||||
foreach(auto &node, _file.nodes) {
|
||||
// collect node transform
|
||||
_file.nodes[nodecount].transforms.push_back(getModelTransform(node));
|
||||
_file.nodes[nodecount].transforms.push_back(getModelTransform(node));
|
||||
if (nodeDependencies[nodecount].size() == 1) {
|
||||
int parentidx = nodeDependencies[nodecount][0];
|
||||
while (true) { // iterate parents
|
||||
// collect parents transforms
|
||||
_file.nodes[nodecount].transforms.push_back(getModelTransform(_file.nodes[parentidx]));
|
||||
_file.nodes[nodecount].transforms.push_back(getModelTransform(_file.nodes[parentidx]));
|
||||
if (nodeDependencies[parentidx].size() == 1) {
|
||||
parentidx = nodeDependencies[parentidx][0];
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nodecount++;
|
||||
}
|
||||
|
||||
|
||||
//Build default joints
|
||||
geometry.joints.resize(1);
|
||||
geometry.joints[0].isFree = false;
|
||||
|
@ -756,7 +756,7 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
setFBXMaterial(fbxMaterial, _file.materials[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
nodecount = 0;
|
||||
// Build meshes
|
||||
|
@ -789,11 +789,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
QVector<glm::vec3> raw_vertices;
|
||||
QVector<glm::vec3> raw_normals;
|
||||
|
||||
bool success = addArrayOfType(indicesBuffer.blob,
|
||||
indicesBufferview.byteOffset + indicesAccBoffset,
|
||||
indicesAccessor.count,
|
||||
part.triangleIndices,
|
||||
indicesAccessor.type,
|
||||
bool success = addArrayOfType(indicesBuffer.blob,
|
||||
indicesBufferview.byteOffset + indicesAccBoffset,
|
||||
indicesAccessor.count,
|
||||
part.triangleIndices,
|
||||
indicesAccessor.type,
|
||||
indicesAccessor.componentType);
|
||||
|
||||
if (!success) {
|
||||
|
@ -813,10 +813,10 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0;
|
||||
if (key == "POSITION") {
|
||||
QVector<float> vertices;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count, vertices,
|
||||
accessor.type,
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count, vertices,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF POSITION data for model " << _url;
|
||||
|
@ -827,11 +827,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
}
|
||||
} else if (key == "NORMAL") {
|
||||
QVector<float> normals;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
normals,
|
||||
accessor.type,
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
normals,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF NORMAL data for model " << _url;
|
||||
|
@ -842,11 +842,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
}
|
||||
} else if (key == "TEXCOORD_0") {
|
||||
QVector<float> texcoords;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
texcoords,
|
||||
accessor.type,
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
texcoords,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_0 data for model " << _url;
|
||||
|
@ -857,11 +857,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
}
|
||||
} else if (key == "TEXCOORD_1") {
|
||||
QVector<float> texcoords;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
texcoords,
|
||||
accessor.type,
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
texcoords,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_1 data for model " << _url;
|
||||
|
@ -888,8 +888,8 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
mesh.meshExtents.addPoint(vertex);
|
||||
geometry.meshExtents.addPoint(vertex);
|
||||
}
|
||||
|
||||
// since mesh.modelTransform seems to not have any effect I apply the transformation the model
|
||||
|
||||
// since mesh.modelTransform seems to not have any effect I apply the transformation the model
|
||||
for (int h = 0; h < mesh.vertices.size(); h++) {
|
||||
glm::vec4 ver = glm::vec4(mesh.vertices[h], 1);
|
||||
if (node.transforms.size() > 0) {
|
||||
|
@ -901,18 +901,18 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
mesh.meshIndex = geometry.meshes.size();
|
||||
FBXReader::buildModelMesh(mesh, url.toString());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
nodecount++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping,
|
||||
FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping,
|
||||
const QUrl& url, bool loadLightmaps, float lightmapLevel) {
|
||||
|
||||
|
||||
_url = url;
|
||||
|
||||
// Normalize url for local files
|
||||
|
@ -928,10 +928,10 @@ FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping
|
|||
FBXGeometry& geometry = *geometryPtr;
|
||||
|
||||
buildGeometry(geometry, url);
|
||||
|
||||
|
||||
//fbxDebugDump(geometry);
|
||||
return geometryPtr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool GLTFReader::readBinary(const QString& url, QByteArray& outdata) {
|
||||
|
@ -940,7 +940,7 @@ bool GLTFReader::readBinary(const QString& url, QByteArray& outdata) {
|
|||
qCDebug(modelformat) << "binaryUrl: " << binaryUrl << " OriginalUrl: " << _url;
|
||||
bool success;
|
||||
std::tie<bool, QByteArray>(success, outdata) = requestData(binaryUrl);
|
||||
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -953,7 +953,8 @@ bool GLTFReader::doesResourceExist(const QString& url) {
|
|||
}
|
||||
|
||||
std::tuple<bool, QByteArray> GLTFReader::requestData(QUrl& url) {
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
nullptr, url, true, -1, "GLTFReader::requestData");
|
||||
|
||||
if (!request) {
|
||||
return std::make_tuple(false, QByteArray());
|
||||
|
@ -999,7 +1000,7 @@ QNetworkReply* GLTFReader::request(QUrl& url, bool isTest) {
|
|||
FBXTexture GLTFReader::getFBXTexture(const GLTFTexture& texture) {
|
||||
FBXTexture fbxtex = FBXTexture();
|
||||
fbxtex.texcoordSet = 0;
|
||||
|
||||
|
||||
if (texture.defined["source"]) {
|
||||
QString url = _file.images[texture.source].uri;
|
||||
QString fname = QUrl(url).fileName();
|
||||
|
@ -1019,10 +1020,10 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia
|
|||
if (material.defined["name"]) {
|
||||
fbxmat.name = fbxmat.materialID = material.name;
|
||||
}
|
||||
|
||||
|
||||
if (material.defined["emissiveFactor"] && material.emissiveFactor.size() == 3) {
|
||||
glm::vec3 emissive = glm::vec3(material.emissiveFactor[0],
|
||||
material.emissiveFactor[1],
|
||||
glm::vec3 emissive = glm::vec3(material.emissiveFactor[0],
|
||||
material.emissiveFactor[1],
|
||||
material.emissiveFactor[2]);
|
||||
fbxmat._material->setEmissive(emissive);
|
||||
}
|
||||
|
@ -1031,12 +1032,12 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia
|
|||
fbxmat.emissiveTexture = getFBXTexture(_file.textures[material.emissiveTexture]);
|
||||
fbxmat.useEmissiveMap = true;
|
||||
}
|
||||
|
||||
|
||||
if (material.defined["normalTexture"]) {
|
||||
fbxmat.normalTexture = getFBXTexture(_file.textures[material.normalTexture]);
|
||||
fbxmat.useNormalMap = true;
|
||||
}
|
||||
|
||||
|
||||
if (material.defined["occlusionTexture"]) {
|
||||
fbxmat.occlusionTexture = getFBXTexture(_file.textures[material.occlusionTexture]);
|
||||
fbxmat.useOcclusionMap = true;
|
||||
|
@ -1044,7 +1045,7 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia
|
|||
|
||||
if (material.defined["pbrMetallicRoughness"]) {
|
||||
fbxmat.isPBSMaterial = true;
|
||||
|
||||
|
||||
if (material.pbrMetallicRoughness.defined["metallicFactor"]) {
|
||||
fbxmat.metallic = material.pbrMetallicRoughness.metallicFactor;
|
||||
}
|
||||
|
@ -1062,23 +1063,23 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia
|
|||
if (material.pbrMetallicRoughness.defined["roughnessFactor"]) {
|
||||
fbxmat._material->setRoughness(material.pbrMetallicRoughness.roughnessFactor);
|
||||
}
|
||||
if (material.pbrMetallicRoughness.defined["baseColorFactor"] &&
|
||||
if (material.pbrMetallicRoughness.defined["baseColorFactor"] &&
|
||||
material.pbrMetallicRoughness.baseColorFactor.size() == 4) {
|
||||
glm::vec3 dcolor = glm::vec3(material.pbrMetallicRoughness.baseColorFactor[0],
|
||||
material.pbrMetallicRoughness.baseColorFactor[1],
|
||||
glm::vec3 dcolor = glm::vec3(material.pbrMetallicRoughness.baseColorFactor[0],
|
||||
material.pbrMetallicRoughness.baseColorFactor[1],
|
||||
material.pbrMetallicRoughness.baseColorFactor[2]);
|
||||
fbxmat.diffuseColor = dcolor;
|
||||
fbxmat._material->setAlbedo(dcolor);
|
||||
fbxmat._material->setOpacity(material.pbrMetallicRoughness.baseColorFactor[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename T, typename L>
|
||||
bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count,
|
||||
bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count,
|
||||
QVector<L>& outarray, int accessorType) {
|
||||
|
||||
|
||||
QDataStream blobstream(bin);
|
||||
blobstream.setByteOrder(QDataStream::LittleEndian);
|
||||
blobstream.setVersion(QDataStream::Qt_5_9);
|
||||
|
@ -1133,9 +1134,9 @@ bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count,
|
|||
return true;
|
||||
}
|
||||
template<typename T>
|
||||
bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count,
|
||||
bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count,
|
||||
QVector<T>& outarray, int accessorType, int componentType) {
|
||||
|
||||
|
||||
switch (componentType) {
|
||||
case GLTFAccessorComponentType::BYTE: {}
|
||||
case GLTFAccessorComponentType::UNSIGNED_BYTE: {
|
||||
|
@ -1157,8 +1158,8 @@ bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count
|
|||
return false;
|
||||
}
|
||||
|
||||
void GLTFReader::retriangulate(const QVector<int>& inIndices, const QVector<glm::vec3>& in_vertices,
|
||||
const QVector<glm::vec3>& in_normals, QVector<int>& outIndices,
|
||||
void GLTFReader::retriangulate(const QVector<int>& inIndices, const QVector<glm::vec3>& in_vertices,
|
||||
const QVector<glm::vec3>& in_normals, QVector<int>& outIndices,
|
||||
QVector<glm::vec3>& out_vertices, QVector<glm::vec3>& out_normals) {
|
||||
for (int i = 0; i < inIndices.size(); i = i + 3) {
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "OBJReader.h"
|
||||
|
||||
#include <ctype.h> // .obj files are not locale-specific. The C/ASCII charset applies.
|
||||
#include <sstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QIODevice>
|
||||
|
@ -263,16 +263,16 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) {
|
|||
default:
|
||||
materials[matName] = currentMaterial;
|
||||
#ifdef WANT_DEBUG
|
||||
qCDebug(modelformat) <<
|
||||
qCDebug(modelformat) <<
|
||||
"OBJ Reader Last material illumination model:" << currentMaterial.illuminationModel <<
|
||||
" shininess:" << currentMaterial.shininess <<
|
||||
" shininess:" << currentMaterial.shininess <<
|
||||
" opacity:" << currentMaterial.opacity <<
|
||||
" diffuse color:" << currentMaterial.diffuseColor <<
|
||||
" specular color:" << currentMaterial.specularColor <<
|
||||
" emissive color:" << currentMaterial.emissiveColor <<
|
||||
" diffuse texture:" << currentMaterial.diffuseTextureFilename <<
|
||||
" specular texture:" << currentMaterial.specularTextureFilename <<
|
||||
" emissive texture:" << currentMaterial.emissiveTextureFilename <<
|
||||
" diffuse color:" << currentMaterial.diffuseColor <<
|
||||
" specular color:" << currentMaterial.specularColor <<
|
||||
" emissive color:" << currentMaterial.emissiveColor <<
|
||||
" diffuse texture:" << currentMaterial.diffuseTextureFilename <<
|
||||
" specular texture:" << currentMaterial.specularTextureFilename <<
|
||||
" emissive texture:" << currentMaterial.emissiveTextureFilename <<
|
||||
" bump texture:" << currentMaterial.bumpTextureFilename <<
|
||||
" opacity texture:" << currentMaterial.opacityTextureFilename;
|
||||
#endif
|
||||
|
@ -352,7 +352,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions) {
|
||||
// Texture options reference http://paulbourke.net/dataformats/mtl/
|
||||
|
@ -443,7 +443,8 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file
|
|||
}
|
||||
|
||||
std::tuple<bool, QByteArray> requestData(QUrl& url) {
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
nullptr, url, true, -1, "(OBJReader) requestData");
|
||||
|
||||
if (!request) {
|
||||
return std::make_tuple(false, QByteArray());
|
||||
|
@ -793,7 +794,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
n0 = checked_at(normals, face.normalIndices[0]);
|
||||
n1 = checked_at(normals, face.normalIndices[1]);
|
||||
n2 = checked_at(normals, face.normalIndices[2]);
|
||||
} else {
|
||||
} else {
|
||||
// generate normals from triangle plane if not provided
|
||||
n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0);
|
||||
}
|
||||
|
@ -923,7 +924,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
bool applyNonMetallic = false;
|
||||
bool fresnelOn = false;
|
||||
|
||||
// Illumination model reference http://paulbourke.net/dataformats/mtl/
|
||||
// Illumination model reference http://paulbourke.net/dataformats/mtl/
|
||||
switch (objMaterial.illuminationModel) {
|
||||
case 0: // Color on and Ambient off
|
||||
// We don't support ambient = do nothing?
|
||||
|
@ -967,7 +968,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
case 10: // Casts shadows onto invisible surfaces
|
||||
// Do nothing?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (applyTransparency) {
|
||||
fbxMaterial.opacity = std::max(fbxMaterial.opacity, ILLUMINATION_MODEL_MIN_OPACITY);
|
||||
|
|
|
@ -456,7 +456,8 @@ void NetworkTexture::makeRequest() {
|
|||
// Add a fragment to the base url so we can identify the section of the ktx being requested when debugging
|
||||
// The actual requested url is _activeUrl and will not contain the fragment
|
||||
_url.setFragment("head");
|
||||
_ktxHeaderRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl);
|
||||
_ktxHeaderRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
this, _activeUrl, true, -1, "NetworkTexture::makeRequest");
|
||||
|
||||
if (!_ktxHeaderRequest) {
|
||||
qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString();
|
||||
|
@ -617,7 +618,8 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
|
|||
|
||||
bool isHighMipRequest = low == NULL_MIP_LEVEL && high == NULL_MIP_LEVEL;
|
||||
|
||||
_ktxMipRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl);
|
||||
_ktxMipRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
this, _activeUrl, true, -1, "NetworkTexture::startMipRangeRequest");
|
||||
|
||||
if (!_ktxMipRequest) {
|
||||
qCWarning(networking).noquote() << "Failed to get request for" << _url.toDisplayString();
|
||||
|
|
|
@ -24,8 +24,12 @@
|
|||
|
||||
static const int DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS = 5;
|
||||
|
||||
AssetResourceRequest::AssetResourceRequest(const QUrl& url) :
|
||||
ResourceRequest(url)
|
||||
AssetResourceRequest::AssetResourceRequest(
|
||||
const QUrl& url,
|
||||
const bool isObservable,
|
||||
const qint64 callerId,
|
||||
const QString& extra) :
|
||||
ResourceRequest(url, isObservable, callerId, extra)
|
||||
{
|
||||
_lastProgressDebug = p_high_resolution_clock::now() - std::chrono::seconds(DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS);
|
||||
}
|
||||
|
@ -35,7 +39,7 @@ AssetResourceRequest::~AssetResourceRequest() {
|
|||
if (_assetMappingRequest) {
|
||||
_assetMappingRequest->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
if (_assetRequest) {
|
||||
_assetRequest->deleteLater();
|
||||
}
|
||||
|
@ -78,7 +82,7 @@ void AssetResourceRequest::requestMappingForPath(const AssetUtils::AssetPath& pa
|
|||
// make sure we'll hear about the result of the get mapping request
|
||||
connect(_assetMappingRequest, &GetMappingRequest::finished, this, [this, path](GetMappingRequest* request){
|
||||
auto statTracker = DependencyManager::get<StatTracker>();
|
||||
|
||||
|
||||
Q_ASSERT(_state == InProgress);
|
||||
Q_ASSERT(request == _assetMappingRequest);
|
||||
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
class AssetResourceRequest : public ResourceRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssetResourceRequest(const QUrl& url);
|
||||
AssetResourceRequest(
|
||||
const QUrl& url,
|
||||
const bool isObservable = true,
|
||||
const qint64 callerId = -1,
|
||||
const QString& extra = "");
|
||||
virtual ~AssetResourceRequest() override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
#include "ResourceManager.h"
|
||||
|
||||
AtpReply::AtpReply(const QUrl& url, QObject* parent) :
|
||||
_resourceRequest(DependencyManager::get<ResourceManager>()->createResourceRequest(parent, url)) {
|
||||
_resourceRequest(DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
parent, url, true, -1, "AtpReply::AtpReply")) {
|
||||
setOperation(QNetworkAccessManager::GetOperation);
|
||||
|
||||
connect(_resourceRequest, &AssetResourceRequest::progress, this, &AtpReply::downloadProgress);
|
||||
|
|
|
@ -12,14 +12,19 @@
|
|||
#ifndef hifi_FileResourceRequest_h
|
||||
#define hifi_FileResourceRequest_h
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
#include "ResourceRequest.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
class FileResourceRequest : public ResourceRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
FileResourceRequest(const QUrl& url) : ResourceRequest(url) { }
|
||||
FileResourceRequest(
|
||||
const QUrlAncestry& urlAncestry,
|
||||
const bool isObservable = true,
|
||||
const qint64 callerId = -1,
|
||||
const QString& extra = ""
|
||||
) : ResourceRequest(urlAncestry, isObservable, callerId, extra) { }
|
||||
|
||||
protected:
|
||||
virtual void doSend() override;
|
||||
|
|
|
@ -13,15 +13,21 @@
|
|||
#define hifi_HTTPResourceRequest_h
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QUrl>
|
||||
#include <QTimer>
|
||||
|
||||
#include "ResourceRequest.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
class HTTPResourceRequest : public ResourceRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
HTTPResourceRequest(const QUrl& url) : ResourceRequest(url) { }
|
||||
HTTPResourceRequest(
|
||||
const QUrlAncestry& urlAncestry,
|
||||
const bool isObservable = true,
|
||||
const qint64 callerId = -1,
|
||||
const QString& = ""
|
||||
) : ResourceRequest(urlAncestry, isObservable, callerId) { }
|
||||
~HTTPResourceRequest();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -22,7 +22,7 @@ QNetworkAccessManager& NetworkAccessManager::getInstance() {
|
|||
if (!networkAccessManagers.hasLocalData()) {
|
||||
networkAccessManagers.setLocalData(new QNetworkAccessManager());
|
||||
}
|
||||
|
||||
|
||||
return *networkAccessManagers.localData();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include "ResourceCache.h"
|
||||
#include "ResourceRequestObserver.h"
|
||||
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
@ -319,7 +320,7 @@ QVariantList ResourceCache::getResourceList() {
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
void ResourceCache::setRequestLimit(uint32_t limit) {
|
||||
auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
|
||||
sharedItems->setRequestLimit(limit);
|
||||
|
@ -336,30 +337,33 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
|||
QReadLocker locker(&_resourcesLock);
|
||||
resource = _resources.value(url).lock();
|
||||
}
|
||||
|
||||
if (resource) {
|
||||
removeUnusedResource(resource);
|
||||
return resource;
|
||||
}
|
||||
|
||||
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
|
||||
return getResource(fallback, QUrl());
|
||||
if (!resource && !url.isValid() && !url.isEmpty() && fallback.isValid()) {
|
||||
resource = getResource(fallback, QUrl());
|
||||
}
|
||||
|
||||
resource = createResource(
|
||||
url,
|
||||
fallback.isValid() ? getResource(fallback, QUrl()) : QSharedPointer<Resource>(),
|
||||
extra);
|
||||
resource->setSelf(resource);
|
||||
resource->setCache(this);
|
||||
resource->moveToThread(qApp->thread());
|
||||
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
|
||||
{
|
||||
QWriteLocker locker(&_resourcesLock);
|
||||
_resources.insert(url, resource);
|
||||
if (!resource) {
|
||||
resource = createResource(
|
||||
url,
|
||||
fallback.isValid() ? getResource(fallback, QUrl()) : QSharedPointer<Resource>(),
|
||||
extra); resource->setSelf(resource);
|
||||
resource->setCache(this);
|
||||
resource->moveToThread(qApp->thread());
|
||||
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
|
||||
{
|
||||
QWriteLocker locker(&_resourcesLock);
|
||||
_resources.insert(url, resource);
|
||||
}
|
||||
removeUnusedResource(resource);
|
||||
resource->ensureLoading();
|
||||
}
|
||||
removeUnusedResource(resource);
|
||||
resource->ensureLoading();
|
||||
|
||||
DependencyManager::get<ResourceRequestObserver>()->update(
|
||||
resource->getURL(), -1, "ResourceCache::getResource");
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
@ -378,7 +382,7 @@ void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource)
|
|||
return;
|
||||
}
|
||||
reserveUnusedResource(resource->getBytes());
|
||||
|
||||
|
||||
resource->setLRUKey(++_lastLRUKey);
|
||||
|
||||
{
|
||||
|
@ -407,7 +411,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
|||
_unusedResourcesSize + resourceSize > _unusedResourcesMaxSize) {
|
||||
// unload the oldest resource
|
||||
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||
|
||||
|
||||
it.value()->setCache(nullptr);
|
||||
auto size = it.value()->getBytes();
|
||||
|
||||
|
@ -473,7 +477,7 @@ void ResourceCache::updateTotalSize(const qint64& deltaSize) {
|
|||
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
|
||||
QList<QSharedPointer<Resource>> ResourceCache::getLoadingRequests() {
|
||||
return DependencyManager::get<ResourceCacheSharedItems>()->getLoadingRequests();
|
||||
}
|
||||
|
@ -494,7 +498,15 @@ bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) {
|
|||
resource->makeRequest();
|
||||
return true;
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
return false;
|
||||
=======
|
||||
|
||||
++_requestsActive;
|
||||
sharedItems->appendActiveRequest(resource);
|
||||
resource->makeRequest();
|
||||
return true;
|
||||
>>>>>>> ac26e68e78... Display resource-access events in marketplace item tester
|
||||
}
|
||||
|
||||
void ResourceCache::requestCompleted(QWeakPointer<Resource> resource) {
|
||||
|
@ -588,7 +600,7 @@ void Resource::refresh() {
|
|||
_request = nullptr;
|
||||
ResourceCache::requestCompleted(_self);
|
||||
}
|
||||
|
||||
|
||||
_activeUrl = _url;
|
||||
init();
|
||||
ensureLoading();
|
||||
|
@ -602,8 +614,13 @@ void Resource::allReferencesCleared() {
|
|||
}
|
||||
|
||||
if (_cache && isCacheable()) {
|
||||
// create and reinsert new shared pointer
|
||||
<<<<<<< HEAD
|
||||
// create and reinsert new shared pointer
|
||||
QSharedPointer<Resource> self(this, &Resource::deleter);
|
||||
=======
|
||||
// create and reinsert new shared pointer
|
||||
QSharedPointer<Resource> self(this, &Resource::allReferencesCleared);
|
||||
>>>>>>> ac26e68e78... Display resource-access events in marketplace item tester
|
||||
setSelf(self);
|
||||
reinsert();
|
||||
|
||||
|
@ -627,10 +644,10 @@ void Resource::init(bool resetLoaded) {
|
|||
_loaded = false;
|
||||
}
|
||||
_attempts = 0;
|
||||
|
||||
|
||||
if (_url.isEmpty()) {
|
||||
_startedLoading = _loaded = true;
|
||||
|
||||
|
||||
} else if (!(_url.isValid())) {
|
||||
_startedLoading = _failedToLoad = true;
|
||||
}
|
||||
|
@ -682,7 +699,8 @@ void Resource::makeRequest() {
|
|||
|
||||
PROFILE_ASYNC_BEGIN(resource, "Resource:" + getType(), QString::number(_requestID), { { "url", _url.toString() }, { "activeURL", _activeUrl.toString() } });
|
||||
|
||||
_request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl);
|
||||
_request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
this, _activeUrl, true, -1, "Resource::makeRequest");
|
||||
|
||||
if (!_request) {
|
||||
qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString();
|
||||
|
@ -751,7 +769,7 @@ void Resource::handleReplyFinished() {
|
|||
} else {
|
||||
handleFailedRequest(result);
|
||||
}
|
||||
|
||||
|
||||
_request->disconnect(this);
|
||||
_request->deleteLater();
|
||||
_request = nullptr;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "NetworkAccessManager.h"
|
||||
#include "NetworkLogging.h"
|
||||
|
||||
|
||||
ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(atpSupportEnabled) {
|
||||
_thread.setObjectName("Resource Manager Thread");
|
||||
|
||||
|
@ -112,22 +113,29 @@ void ResourceManager::cleanup() {
|
|||
_thread.wait();
|
||||
}
|
||||
|
||||
ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) {
|
||||
ResourceRequest* ResourceManager::createResourceRequest(
|
||||
QObject* parent,
|
||||
const QUrl& url,
|
||||
const bool isObservable,
|
||||
const qint64 callerId,
|
||||
const QString& extra
|
||||
) {
|
||||
auto normalizedURL = normalizeURL(url);
|
||||
auto scheme = normalizedURL.scheme();
|
||||
|
||||
ResourceRequest* request = nullptr;
|
||||
|
||||
qDebug() << "!!!! in createResourceRequest " << callerId;
|
||||
if (scheme == URL_SCHEME_FILE || scheme == URL_SCHEME_QRC) {
|
||||
request = new FileResourceRequest(normalizedURL);
|
||||
request = new FileResourceRequest(normalizedURL, isObservable, callerId, extra);
|
||||
} else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) {
|
||||
request = new HTTPResourceRequest(normalizedURL);
|
||||
request = new HTTPResourceRequest(normalizedURL, isObservable, callerId, extra);
|
||||
} else if (scheme == URL_SCHEME_ATP) {
|
||||
if (!_atpSupportEnabled) {
|
||||
qCDebug(networking) << "ATP support not enabled, unable to create request for URL: " << url.url();
|
||||
return nullptr;
|
||||
}
|
||||
request = new AssetResourceRequest(normalizedURL);
|
||||
request = new AssetResourceRequest(normalizedURL, isObservable, callerId, extra);
|
||||
} else {
|
||||
qCDebug(networking) << "Unknown scheme (" << scheme << ") for URL: " << url.url();
|
||||
return nullptr;
|
||||
|
@ -138,6 +146,7 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q
|
|||
QObject::connect(parent, &QObject::destroyed, request, &QObject::deleteLater);
|
||||
}
|
||||
request->moveToThread(&_thread);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
|
@ -163,7 +172,7 @@ bool ResourceManager::resourceExists(const QUrl& url) {
|
|||
|
||||
return reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200;
|
||||
} else if (scheme == URL_SCHEME_ATP && _atpSupportEnabled) {
|
||||
auto request = new AssetResourceRequest(url);
|
||||
auto request = new AssetResourceRequest(url, ResourceRequest::IS_NOT_OBSERVABLE);
|
||||
ByteRange range;
|
||||
range.fromInclusive = 1;
|
||||
range.toExclusive = 1;
|
||||
|
|
|
@ -34,7 +34,12 @@ public:
|
|||
QString normalizeURL(const QString& urlString);
|
||||
QUrl normalizeURL(const QUrl& url);
|
||||
|
||||
ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url);
|
||||
ResourceRequest* createResourceRequest(
|
||||
QObject* parent,
|
||||
const QUrl& url,
|
||||
const bool isObservable = true,
|
||||
const qint64 callerId = -1,
|
||||
const QString& extra = "");
|
||||
|
||||
void init();
|
||||
void cleanup();
|
||||
|
|
|
@ -10,15 +10,20 @@
|
|||
//
|
||||
|
||||
#include "ResourceRequest.h"
|
||||
#include "ResourceRequestObserver.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <StatTracker.h>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
ResourceRequest::ResourceRequest(const QUrl& url) : _url(url) { }
|
||||
|
||||
void ResourceRequest::send() {
|
||||
if (_isObservable) {
|
||||
DependencyManager::get<ResourceRequestObserver>()->update(
|
||||
_urlAncestry, _callerId, _extra + " => ResourceRequest::send" );
|
||||
}
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection);
|
||||
return;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <cstdint>
|
||||
|
||||
#include "ByteRange.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
const QString STAT_ATP_REQUEST_STARTED = "StartedATPRequest";
|
||||
const QString STAT_HTTP_REQUEST_STARTED = "StartedHTTPRequest";
|
||||
|
@ -40,7 +42,21 @@ const QString STAT_FILE_RESOURCE_TOTAL_BYTES = "FILEBytesDownloaded";
|
|||
class ResourceRequest : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ResourceRequest(const QUrl& url);
|
||||
static const bool IS_OBSERVABLE = true;
|
||||
static const bool IS_NOT_OBSERVABLE = false;
|
||||
|
||||
ResourceRequest(
|
||||
const QUrlAncestry& urlAncestry,
|
||||
const bool isObservable = IS_OBSERVABLE,
|
||||
const qint64 callerId = -1,
|
||||
const QString& extra = ""
|
||||
) : _urlAncestry(urlAncestry),
|
||||
_isObservable(isObservable),
|
||||
_callerId(callerId),
|
||||
_extra(extra),
|
||||
_url(urlAncestry.last())
|
||||
{ }
|
||||
|
||||
virtual ~ResourceRequest() = default;
|
||||
|
||||
enum State {
|
||||
|
@ -87,6 +103,7 @@ protected:
|
|||
virtual void doSend() = 0;
|
||||
void recordBytesDownloadedInStats(const QString& statName, int64_t bytesReceived);
|
||||
|
||||
|
||||
QUrl _url;
|
||||
QUrl _relativePathURL;
|
||||
State _state { NotStarted };
|
||||
|
@ -99,6 +116,10 @@ protected:
|
|||
bool _rangeRequestSuccessful { false };
|
||||
uint64_t _totalSizeOfResource { 0 };
|
||||
int64_t _lastRecordedBytesDownloaded { 0 };
|
||||
bool _isObservable;
|
||||
qint64 _callerId;
|
||||
QString _extra;
|
||||
QUrlAncestry _urlAncestry;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -669,7 +669,7 @@ OctreeElementPointer Octree::getElementEnclosingPoint(const glm::vec3& point, Oc
|
|||
return args.element;
|
||||
}
|
||||
|
||||
bool Octree::readFromFile(const char* fileName) {
|
||||
bool Octree::readFromFile(const char* fileName, const QUrlAncestry& urlAncestry) {
|
||||
QString qFileName = findMostRecentFileExtension(fileName, PERSIST_EXTENSIONS);
|
||||
|
||||
if (qFileName.endsWith(".json.gz")) {
|
||||
|
@ -689,7 +689,7 @@ bool Octree::readFromFile(const char* fileName) {
|
|||
|
||||
qCDebug(octree) << "Loading file" << qFileName << "...";
|
||||
|
||||
bool success = readFromStream(fileLength, fileInputStream);
|
||||
bool success = readFromStream(fileLength, fileInputStream, "", urlAncestry);
|
||||
|
||||
file.close();
|
||||
|
||||
|
@ -734,11 +734,18 @@ QString getMarketplaceID(const QString& urlString) {
|
|||
return QString();
|
||||
}
|
||||
|
||||
bool Octree::readFromURL(const QString& urlString) {
|
||||
bool Octree::readFromURL(
|
||||
const QString& urlString,
|
||||
const bool isObservable,
|
||||
const qint64 callerId,
|
||||
const QUrlAncestry& urlAncestry
|
||||
) {
|
||||
QString trimmedUrl = urlString.trimmed();
|
||||
QString marketplaceID = getMarketplaceID(trimmedUrl);
|
||||
auto request =
|
||||
std::unique_ptr<ResourceRequest>(DependencyManager::get<ResourceManager>()->createResourceRequest(this, trimmedUrl));
|
||||
qDebug() << "!!!!! going to createResourceRequest " << callerId;
|
||||
auto request = std::unique_ptr<ResourceRequest>(
|
||||
DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
this, trimmedUrl, isObservable, callerId, "Octree::readFromURL"));
|
||||
|
||||
if (!request) {
|
||||
return false;
|
||||
|
@ -760,15 +767,20 @@ bool Octree::readFromURL(const QString& urlString) {
|
|||
|
||||
if (wasCompressed) {
|
||||
QDataStream inputStream(uncompressedJsonData);
|
||||
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID);
|
||||
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, urlAncestry);
|
||||
}
|
||||
|
||||
QDataStream inputStream(data);
|
||||
return readFromStream(data.size(), inputStream, marketplaceID);
|
||||
return readFromStream(data.size(), inputStream, marketplaceID, urlAncestry);
|
||||
}
|
||||
|
||||
|
||||
bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID) {
|
||||
bool Octree::readFromStream(
|
||||
uint64_t streamLength,
|
||||
QDataStream& inputStream,
|
||||
const QString& marketplaceID,
|
||||
const QUrlAncestry& urlAncestry
|
||||
) {
|
||||
// decide if this is binary SVO or JSON-formatted SVO
|
||||
QIODevice *device = inputStream.device();
|
||||
char firstChar;
|
||||
|
@ -780,7 +792,7 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con
|
|||
return false;
|
||||
} else {
|
||||
qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength;
|
||||
return readJSONFromStream(streamLength, inputStream, marketplaceID);
|
||||
return readJSONFromStream(streamLength, inputStream, marketplaceID, urlAncestry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -809,7 +821,12 @@ QJsonDocument addMarketplaceIDToDocumentEntities(QJsonDocument& doc, const QStri
|
|||
|
||||
const int READ_JSON_BUFFER_SIZE = 2048;
|
||||
|
||||
bool Octree::readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID /*=""*/) {
|
||||
bool Octree::readJSONFromStream(
|
||||
uint64_t streamLength,
|
||||
QDataStream& inputStream,
|
||||
const QString& marketplaceID, /*=""*/
|
||||
const QUrlAncestry& urlAncestry
|
||||
) {
|
||||
// if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until
|
||||
// we get an eof. Leave streamLength parameter for consistency.
|
||||
|
||||
|
@ -834,7 +851,7 @@ bool Octree::readJSONFromStream(uint64_t streamLength, QDataStream& inputStream,
|
|||
}
|
||||
QVariant asVariant = asDocument.toVariant();
|
||||
QVariantMap asMap = asVariant.toMap();
|
||||
bool success = readFromMap(asMap);
|
||||
bool success = readFromMap(asMap, urlAncestry);
|
||||
delete[] rawData;
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "OctreePacketData.h"
|
||||
#include "OctreeSceneStats.h"
|
||||
#include "OctreeUtils.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
class ReadBitstreamToTreeParams;
|
||||
class Octree;
|
||||
|
@ -209,13 +210,13 @@ public:
|
|||
bool skipThoseWithBadParents) = 0;
|
||||
|
||||
// Octree importers
|
||||
bool readFromFile(const char* filename);
|
||||
bool readFromURL(const QString& url); // will support file urls as well...
|
||||
bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="");
|
||||
bool readFromFile(const char* filename, const QUrlAncestry& urlAncestry = {});
|
||||
bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const QUrlAncestry& urlAncestry = {}); // will support file urls as well...
|
||||
bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const QUrlAncestry& urlAncestry = {});
|
||||
bool readSVOFromStream(uint64_t streamLength, QDataStream& inputStream);
|
||||
bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="");
|
||||
bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const QUrlAncestry& urlAncestry = {});
|
||||
bool readJSONFromGzippedFile(QString qFileName);
|
||||
virtual bool readFromMap(QVariantMap& entityDescription) = 0;
|
||||
virtual bool readFromMap(QVariantMap& entityDescription, const QUrlAncestry& urlAncestry = {}) = 0;
|
||||
|
||||
uint64_t getOctreeElementsCount();
|
||||
|
||||
|
|
|
@ -258,24 +258,29 @@ void OffscreenSurface::setMaxFps(uint8_t maxFps) {
|
|||
}
|
||||
|
||||
void OffscreenSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) {
|
||||
qDebug() << "Here 1";
|
||||
loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) {
|
||||
QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem));
|
||||
});
|
||||
}
|
||||
|
||||
void OffscreenSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& callback) {
|
||||
qDebug() << "Here 2";
|
||||
loadInternal(qmlSource, createNewContext, nullptr, callback);
|
||||
}
|
||||
|
||||
void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback, const QmlContextCallback& contextCallback) {
|
||||
qDebug() << "Here 3";
|
||||
loadInternal(qmlSource, true, nullptr, callback, contextCallback);
|
||||
}
|
||||
|
||||
void OffscreenSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& callback) {
|
||||
qDebug() << "Here 4";
|
||||
load(qmlSource, false, callback);
|
||||
}
|
||||
|
||||
void OffscreenSurface::load(const QString& qmlSourceFile, const QmlContextObjectCallback& callback) {
|
||||
qDebug() << "Here 5";
|
||||
return load(QUrl(qmlSourceFile), callback);
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool
|
|||
tempDir = zipTemp.path();
|
||||
path.remove("file:///");
|
||||
}
|
||||
|
||||
|
||||
qCDebug(scriptengine) << "Temporary directory at: " + tempDir;
|
||||
if (!isTempDir(tempDir)) {
|
||||
qCDebug(scriptengine) << "Temporary directory mismatch; risk of losing files";
|
||||
|
@ -58,7 +58,7 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool
|
|||
}
|
||||
|
||||
QStringList fileList = unzipFile(path, tempDir);
|
||||
|
||||
|
||||
if (!fileList.isEmpty()) {
|
||||
qCDebug(scriptengine) << "First file to upload: " + fileList.first();
|
||||
} else {
|
||||
|
@ -138,7 +138,8 @@ QString FileScriptingInterface::convertUrlToPath(QUrl url) {
|
|||
// this function is not in use
|
||||
void FileScriptingInterface::downloadZip(QString path, const QString link) {
|
||||
QUrl url = QUrl(link);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
nullptr, url, true, -1, "FileScriptingInterface::downloadZip");
|
||||
connect(request, &ResourceRequest::finished, this, [this, path]{
|
||||
unzipFile(path, ""); // so intellisense isn't mad
|
||||
});
|
||||
|
|
|
@ -109,7 +109,8 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable
|
|||
#ifdef THREAD_DEBUGGING
|
||||
qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
nullptr, url, true, -1, "ScriptCache::getScriptContents");
|
||||
Q_ASSERT(request);
|
||||
request->setCacheEnabled(!forceDownload);
|
||||
connect(request, &ResourceRequest::finished, this, [=]{ scriptContentAvailable(maxRetries); });
|
||||
|
@ -166,7 +167,8 @@ void ScriptCache::scriptContentAvailable(int maxRetries) {
|
|||
qCDebug(scriptengine) << QString("Retrying script request [%1 / %2]: %3")
|
||||
.arg(attempt).arg(maxRetries).arg(url.toString());
|
||||
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
|
||||
nullptr, url, true, -1, "ScriptCache::scriptContentAvailable");
|
||||
Q_ASSERT(request);
|
||||
|
||||
// We've already made a request, so the cache must be disabled or it wasn't there, so enabling
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <NetworkAccessManager.h>
|
||||
#include <NetworkingConstants.h>
|
||||
|
||||
#include "ResourceRequestObserver.h"
|
||||
#include "ScriptEngine.h"
|
||||
|
||||
const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/";
|
||||
|
@ -62,7 +63,7 @@ QScriptValue XMLHttpRequestClass::constructor(QScriptContext* context, QScriptEn
|
|||
QScriptValue XMLHttpRequestClass::getStatus() const {
|
||||
if (_reply) {
|
||||
return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
|
||||
}
|
||||
}
|
||||
return QScriptValue(0);
|
||||
}
|
||||
|
||||
|
@ -143,7 +144,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
|
|||
|
||||
if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
|
||||
if (accountManager->hasValidAccessToken()) {
|
||||
static const QString HTTP_AUTHORIZATION_HEADER = "Authorization";
|
||||
QString bearerString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
|
||||
|
@ -189,7 +190,7 @@ void XMLHttpRequestClass::send(const QScriptValue& data) {
|
|||
}
|
||||
|
||||
void XMLHttpRequestClass::doSend() {
|
||||
|
||||
DependencyManager::get<ResourceRequestObserver>()->update(_url, -1, "XMLHttpRequestClass::doSend");
|
||||
_reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData);
|
||||
connectToReply(_reply);
|
||||
|
||||
|
|
31
libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h
Normal file
31
libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// EntityItemWeakPointerWithUrlAncestry.h
|
||||
// libraries/shared/src/
|
||||
//
|
||||
// Created by Kerry Ivan Kurian 10/15/18
|
||||
// Copyright 2018 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
|
||||
//
|
||||
|
||||
#ifndef hifi_EntityItemWeakPointerWithUrlAncestry_h
|
||||
#define hifi_EntityItemWeakPointerWithUrlAncestry_h
|
||||
|
||||
#include "EntityTypes.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
struct EntityItemWeakPointerWithUrlAncestry {
|
||||
EntityItemWeakPointerWithUrlAncestry(
|
||||
const EntityItemWeakPointer& a,
|
||||
const QUrlAncestry& b
|
||||
) : entityItemWeakPointer(a), urlAncestry(b) {}
|
||||
|
||||
EntityItemWeakPointer entityItemWeakPointer;
|
||||
QUrlAncestry urlAncestry;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_EntityItemWeakPointerWithUrlAncestry_h
|
||||
|
35
libraries/shared/src/QUrlAncestry.cpp
Normal file
35
libraries/shared/src/QUrlAncestry.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// QUrlAncestry.cpp
|
||||
// libraries/shared/src/
|
||||
//
|
||||
// Created by Kerry Ivan Kurian on 10/12/18.
|
||||
// Copyright (c) 2018 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
QUrlAncestry::QUrlAncestry(const QUrl& resource, const QUrl& referrer) {
|
||||
this->append(referrer);
|
||||
this->append(resource);
|
||||
}
|
||||
|
||||
QUrlAncestry::QUrlAncestry(
|
||||
const QUrl& resource,
|
||||
const QUrlAncestry& ancestors) : QVector<QUrl>(ancestors)
|
||||
{
|
||||
this->append(resource);
|
||||
}
|
||||
|
||||
void QUrlAncestry::toJson(QJsonArray& array) const {
|
||||
for (auto const& qurl : *this) {
|
||||
array.append(qurl.toDisplayString());
|
||||
}
|
||||
}
|
||||
|
||||
const QUrl QUrlAncestry::url() const {
|
||||
return this->last();
|
||||
}
|
32
libraries/shared/src/QUrlAncestry.h
Normal file
32
libraries/shared/src/QUrlAncestry.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// QUrlAncestry.h
|
||||
// libraries/shared/src/
|
||||
//
|
||||
// Created by Kerry Ivan Kurian on 10/12/18.
|
||||
// Copyright (c) 2018 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#ifndef hifi_QUrlAncestry_H
|
||||
#define hifi_QUrlAncestry_H
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QUrl>
|
||||
#include <QVector>
|
||||
|
||||
|
||||
class QUrlAncestry : public QVector<QUrl> {
|
||||
public:
|
||||
QUrlAncestry() {}
|
||||
QUrlAncestry(const QUrl& resource, const QUrl& referrer = QUrl("__NONE__"));
|
||||
QUrlAncestry(const QUrl& resource, const QUrlAncestry& ancestors);
|
||||
|
||||
void toJson(QJsonArray& array) const;
|
||||
const QUrl url() const;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_QUrlVector_H
|
38
libraries/shared/src/ResourceRequestObserver.cpp
Normal file
38
libraries/shared/src/ResourceRequestObserver.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// ResourceAccessMonitor.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Kerry Ivan Kurian on 9/27/18.
|
||||
// Copyright 2018 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 <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include "ResourceRequestObserver.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
// void ResourceRequestObserver::update(const QNetworkRequest& request, const qint64 callerId, const QString& extra) {
|
||||
// update(QUrlAncestry(request.url()), callerId, extra);
|
||||
// }
|
||||
|
||||
void ResourceRequestObserver::update(
|
||||
const QUrlAncestry& urlAncestry,
|
||||
const qint64 callerId,
|
||||
const QString& extra
|
||||
) {
|
||||
QJsonArray array;
|
||||
urlAncestry.toJson(array);
|
||||
QJsonObject data {
|
||||
{ "url", array },
|
||||
{ "callerId", callerId },
|
||||
{ "extra", extra }
|
||||
};
|
||||
emit resourceRequestEvent(data.toVariantMap());
|
||||
}
|
31
libraries/shared/src/ResourceRequestObserver.h
Normal file
31
libraries/shared/src/ResourceRequestObserver.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ResourceRequestObserver.h
|
||||
// libraries/commerce/src
|
||||
//
|
||||
// Created by Kerry Ivan Kurian on 9/27/18.
|
||||
// Copyright 2018 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 <QJsonObject>
|
||||
#include <QString>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
#include "DependencyManager.h"
|
||||
#include "QUrlAncestry.h"
|
||||
|
||||
|
||||
class ResourceRequestObserver : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
// void update(const QNetworkRequest& request, const qint64 callerId = -1, const QString& extra = "");
|
||||
void update(const QUrlAncestry& urlAncestry, const qint64 callerId = -1, const QString& extra = "");
|
||||
|
||||
signals:
|
||||
void resourceRequestEvent(QVariantMap result);
|
||||
};
|
|
@ -49,6 +49,33 @@ var NO_BUTTON = 0; // QMessageBox::NoButton
|
|||
|
||||
var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't write to \nthe domain's Asset Server.";
|
||||
|
||||
|
||||
var resourceRequestEvents = [];
|
||||
function signalResourceRequestEvent(data) {
|
||||
ui.tablet.sendToQml({
|
||||
method: "resourceRequestEvent",
|
||||
data: data });
|
||||
}
|
||||
|
||||
function onResourceRequestEvent(data) {
|
||||
var resourceRequestEvent = {
|
||||
"date": JSON.stringify(new Date()),
|
||||
"url": data.url,
|
||||
"callerId": data.callerId,
|
||||
"extra": data.extra };
|
||||
resourceRequestEvents.push(resourceRequestEvent);
|
||||
signalResourceRequestEvent(resourceRequestEvent);
|
||||
}
|
||||
|
||||
function pushResourceRequestEvents() {
|
||||
var length = resourceRequestEvents.length
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (i in resourceRequestEvents) {
|
||||
signalResourceRequestEvent(resourceRequestEvents[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onMessageBoxClosed(id, button) {
|
||||
if (id === messageBox && button === CANCEL_BUTTON) {
|
||||
isDownloadBeingCancelled = true;
|
||||
|
@ -522,13 +549,19 @@ function getPositionToCreateEntity(extra) {
|
|||
return position;
|
||||
}
|
||||
|
||||
function rezEntity(itemHref, itemType) {
|
||||
function defaultFor(arg, val) {
|
||||
return typeof arg !== 'undefined' ? arg : val;
|
||||
}
|
||||
|
||||
function rezEntity(itemHref, itemType, marketplaceItemTesterId) {
|
||||
var isWearable = itemType === "wearable";
|
||||
var success = Clipboard.importEntities(itemHref);
|
||||
print("!!!!! Clipboard.importEntities " + marketplaceItemTesterId);
|
||||
var success = Clipboard.importEntities(itemHref, true, marketplaceItemTesterId);
|
||||
var wearableLocalPosition = null;
|
||||
var wearableLocalRotation = null;
|
||||
var wearableLocalDimensions = null;
|
||||
var wearableDimensions = null;
|
||||
marketplaceItemTesterId = defaultFor(marketplaceItemTesterId, -1);
|
||||
|
||||
if (itemType === "contentSet") {
|
||||
console.log("Item is a content set; codepath shouldn't go here.");
|
||||
|
@ -877,11 +910,12 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
|
|||
case 'checkout_rezClicked':
|
||||
case 'purchases_rezClicked':
|
||||
case 'tester_rezClicked':
|
||||
rezEntity(message.itemHref, message.itemType);
|
||||
print("!!!!! marketplaces tester_rezClicked");
|
||||
rezEntity(message.itemHref, message.itemType, message.itemId);
|
||||
break;
|
||||
case 'tester_newResourceObject':
|
||||
var resourceObject = message.resourceObject;
|
||||
resourceObjectsInTest[resourceObject.id] = resourceObject;
|
||||
resourceObjectsInTest[resourceObject.resourceObjectId] = resourceObject;
|
||||
signalNewResourceObjectInTest(resourceObject);
|
||||
break;
|
||||
case 'tester_updateResourceObjectAssetType':
|
||||
|
@ -1029,16 +1063,20 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
|
|||
};
|
||||
|
||||
function pushResourceObjectsInTest() {
|
||||
var maxObjectId = -1;
|
||||
for (var objectId in resourceObjectsInTest) {
|
||||
signalNewResourceObjectInTest(resourceObjectsInTest[objectId]);
|
||||
maxObjectId = (maxObjectId < objectId) ? parseInt(objectId) : maxObjectId;
|
||||
var maxResourceObjectId = -1;
|
||||
var length = resourceObjectsInTest.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (i in resourceObjectsInTest) {
|
||||
signalNewResourceObjectInTest(resourceObjectsInTest[i]);
|
||||
var resourceObjectId = resourceObjectsInTest[i].resourceObjectId;
|
||||
maxResourceObjectId = (maxResourceObjectId < resourceObjectId) ? parseInt(resourceObjectId) : maxResourceObjectId;
|
||||
}
|
||||
}
|
||||
// N.B. Thinking about removing the following sendToQml? Be sure
|
||||
// that the marketplace item tester QML has heard from us, at least
|
||||
// so that it can indicate to the user that all of the resoruce
|
||||
// objects in test have been transmitted to it.
|
||||
ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxObjectId + 1 });
|
||||
ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxResourceObjectId + 1 });
|
||||
}
|
||||
|
||||
// Function Name: onTabletScreenChanged()
|
||||
|
@ -1127,6 +1165,7 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) {
|
|||
// variable amount of time to come up, in practice less than
|
||||
// 750ms.
|
||||
Script.setTimeout(pushResourceObjectsInTest, 750);
|
||||
Script.setTimeout(pushResourceRequestEvents, 750);
|
||||
}
|
||||
|
||||
console.debug(ui.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type +
|
||||
|
@ -1193,6 +1232,7 @@ function startup() {
|
|||
ui.tablet.webEventReceived.connect(onWebEventReceived);
|
||||
Wallet.walletStatusChanged.connect(sendCommerceSettings);
|
||||
Window.messageBoxClosed.connect(onMessageBoxClosed);
|
||||
ResourceRequestObserver.resourceRequestEvent.connect(onResourceRequestEvent);
|
||||
|
||||
Wallet.refreshWalletStatus();
|
||||
}
|
||||
|
@ -1226,6 +1266,7 @@ function shutdown() {
|
|||
GlobalServices.myUsernameChanged.disconnect(onUsernameChanged);
|
||||
Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged);
|
||||
ContextOverlay.contextOverlayClicked.disconnect(openInspectionCertificateQML);
|
||||
ResourceRequestObserver.resourceRequestEvent.disconnect(onResourceRequestEvent);
|
||||
|
||||
off();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue