mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Return ScriptableResource from prefetch
This commit is contained in:
parent
3c7fc95d6c
commit
8ad8b5d0d9
3 changed files with 105 additions and 27 deletions
|
@ -119,6 +119,57 @@ QSharedPointer<Resource> ResourceCacheSharedItems::getHighestPendingRequest() {
|
|||
return highestResource;
|
||||
}
|
||||
|
||||
ScriptableResource::ScriptableResource(const QSharedPointer<Resource>& resource) :
|
||||
QObject(nullptr),
|
||||
_resource(resource) {}
|
||||
|
||||
void ScriptableResource::finished(bool success) {
|
||||
if (_progressConnection) {
|
||||
disconnect(_progressConnection);
|
||||
}
|
||||
if (_finishedConnection) {
|
||||
disconnect(_finishedConnection);
|
||||
}
|
||||
|
||||
_isLoaded = true;
|
||||
_isFailed = !success;
|
||||
|
||||
if (_isFailed) {
|
||||
emit failedChanged(_isFailed);
|
||||
}
|
||||
emit loadedChanged(_isLoaded);
|
||||
}
|
||||
|
||||
ScriptableResource* ResourceCache::prefetch(const QUrl& url) {
|
||||
auto result = new ScriptableResource();
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
// Must be called in thread to ensure getResource returns a valid pointer
|
||||
QMetaObject::invokeMethod(this, "prefetch", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(ScriptableResource*, result), Q_ARG(QUrl, url));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
auto resource = getResource(url);
|
||||
result->_resource = resource;
|
||||
result->setObjectName(url.toString());
|
||||
|
||||
result->_resource = resource;
|
||||
if (resource->isLoaded()) {
|
||||
result->finished(!resource->_failedToLoad);
|
||||
} else {
|
||||
result->_progressConnection = connect(
|
||||
resource.data(), &Resource::handleDownloadProgress,
|
||||
result, &ScriptableResource::progressChanged);
|
||||
result->_finishedConnection = connect(
|
||||
resource.data(), &Resource::finished,
|
||||
result, &ScriptableResource::finished);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ResourceCache::ResourceCache(QObject* parent) : QObject(parent) {
|
||||
auto& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain,
|
||||
|
@ -169,11 +220,6 @@ void ResourceCache::clearATPAssets() {
|
|||
}
|
||||
|
||||
void ResourceCache::refreshAll() {
|
||||
// Remove refs to prefetching resources
|
||||
_prefetchingResourcesLock.lock();
|
||||
_prefetchingResources.clear();
|
||||
_prefetchingResourcesLock.unlock();
|
||||
|
||||
// Clear all unused resources so we don't have to reload them
|
||||
clearUnusedResource();
|
||||
resetResourceCounters();
|
||||
|
@ -221,24 +267,7 @@ QVariantList ResourceCache::getResourceList() {
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
void ResourceCache::prefetch(const QUrl& url) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "prefetch", Q_ARG(QUrl, url));
|
||||
} else {
|
||||
auto resource = getResource(url);
|
||||
// If it is not loaded, hold a ref until it is
|
||||
if (!resource->isLoaded()) {
|
||||
QMutexLocker lock(&_prefetchingResourcesLock);
|
||||
_prefetchingResources.insert(url, resource);
|
||||
connect(resource.data(), &Resource::finishedLoading, [this, url]{
|
||||
QMutexLocker lock(&_prefetchingResourcesLock);
|
||||
this->_prefetchingResources.remove(url);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ResourceCache::setRequestLimit(int limit) {
|
||||
_requestLimit = limit;
|
||||
|
||||
|
|
|
@ -78,6 +78,40 @@ private:
|
|||
QList<QWeakPointer<Resource>> _loadingRequests;
|
||||
};
|
||||
|
||||
/// Wrapper to expose resources to JS/QML
|
||||
class ScriptableResource : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool loaded READ isLoaded NOTIFY loadedChanged)
|
||||
Q_PROPERTY(bool failed READ isFailed NOTIFY failedChanged)
|
||||
public:
|
||||
ScriptableResource(const QSharedPointer<Resource>& resource = QSharedPointer<Resource>());
|
||||
virtual ~ScriptableResource() = default;
|
||||
|
||||
bool isLoaded() const { return _isLoaded; }
|
||||
bool isFailed() const { return _isFailed; }
|
||||
|
||||
signals:
|
||||
void progressChanged(uint64_t bytesReceived, uint64_t bytesTotal);
|
||||
void loadedChanged(bool loaded); // analogous to &Resource::finished
|
||||
void failedChanged(bool failed);
|
||||
|
||||
private slots:
|
||||
void finished(bool success);
|
||||
|
||||
private:
|
||||
friend class ResourceCache;
|
||||
|
||||
// Holds a ref to the resource to keep it in scope
|
||||
QSharedPointer<Resource> _resource;
|
||||
|
||||
QMetaObject::Connection _progressConnection;
|
||||
QMetaObject::Connection _finishedConnection;
|
||||
|
||||
bool _isLoaded{ false };
|
||||
bool _isFailed{ false };
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ScriptableResource*);
|
||||
|
||||
/// Base class for resource caches.
|
||||
class ResourceCache : public QObject {
|
||||
|
@ -96,7 +130,8 @@ public:
|
|||
|
||||
Q_INVOKABLE QVariantList getResourceList();
|
||||
|
||||
Q_INVOKABLE void prefetch(const QUrl& url);
|
||||
// This must be exposed as a ptr so the ScriptEngine may take ownership
|
||||
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url);
|
||||
|
||||
static void setRequestLimit(int limit);
|
||||
static int getRequestLimit() { return _requestLimit; }
|
||||
|
@ -177,9 +212,6 @@ private:
|
|||
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
||||
QReadWriteLock _unusedResourcesLock { QReadWriteLock::Recursive };
|
||||
QMap<int, QSharedPointer<Resource>> _unusedResources;
|
||||
|
||||
QMutex _prefetchingResourcesLock{ QMutex::Recursive };
|
||||
QMap<QUrl, QSharedPointer<Resource>> _prefetchingResources;
|
||||
};
|
||||
|
||||
/// Base class for resources.
|
||||
|
@ -292,6 +324,7 @@ private:
|
|||
void reinsert();
|
||||
|
||||
friend class ResourceCache;
|
||||
friend class ScriptableResource;
|
||||
|
||||
ResourceRequest* _request = nullptr;
|
||||
int _lruKey = 0;
|
||||
|
|
|
@ -270,6 +270,20 @@ static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantR
|
|||
assert(false);
|
||||
}
|
||||
|
||||
// Templated qScriptRegisterMetaType fails to compile with raw pointers
|
||||
using ScriptableResourceRawPtr = ScriptableResource*;
|
||||
|
||||
static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine, const ScriptableResourceRawPtr& resource) {
|
||||
auto object = engine->newQObject(
|
||||
const_cast<ScriptableResourceRawPtr>(resource),
|
||||
QScriptEngine::ScriptOwnership);
|
||||
return object;
|
||||
}
|
||||
|
||||
static void scriptableResourceFromScriptValue(const QScriptValue& value, ScriptableResourceRawPtr& resource) {
|
||||
resource = static_cast<ScriptableResourceRawPtr>(value.toQObject());
|
||||
}
|
||||
|
||||
void ScriptEngine::init() {
|
||||
if (_isInitialized) {
|
||||
return; // only initialize once
|
||||
|
@ -332,6 +346,8 @@ void ScriptEngine::init() {
|
|||
qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue);
|
||||
qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue);
|
||||
|
||||
qScriptRegisterMetaType(this, scriptableResourceToScriptValue, scriptableResourceFromScriptValue);
|
||||
|
||||
// constants
|
||||
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
||||
|
||||
|
|
Loading…
Reference in a new issue