more work on proper threading of ScriptEngine

This commit is contained in:
Brad Hefta-Gaub 2015-09-14 20:26:04 -07:00
parent 18fbf896f1
commit a3c0288eae
6 changed files with 152 additions and 117 deletions

View file

@ -4226,25 +4226,12 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
if (scriptFilename.isNull()) {
// This appears to be the script engine used by the script widget's evaluation window before the file has been saved...
qDebug() << "############################# HELLO WE ARE HERE!!!! ##################################";
// this had better be the script editor (we should de-couple so somebody who thinks they are loading a script
// doesn't just get an empty script engine)
// we can complete setup now since there isn't a script we have to load
registerScriptEngineWithApplicationServices(scriptEngine);
scriptEngine->runInThread();
//FIXME - intentionally attempting to test thread safe call to registerGlobalObject()
qDebug() << "about to attempt to call registerGlobalObject on wrong thread!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
scriptEngine->registerGlobalObject("LODManager2", DependencyManager::get<LODManager>().data());
qDebug() << "about to attempt to call registerFunction on wrong thread!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
scriptEngine->registerFunction("WebWindow2", WebWindowClass::constructor, 1);
qDebug() << "about to attempt to call registerGetterSetter on wrong thread!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
scriptEngine->registerGetterSetter("foo_location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter);
} else {
// connect to the appropriate signals of this script engine
connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &Application::handleScriptEngineLoaded);
@ -4267,8 +4254,8 @@ void Application::reloadScript(const QString& scriptName, bool isUserLoaded) {
loadScript(scriptName, isUserLoaded, false, false, true);
}
// FIXME - change to new version of ScriptCache loading notification
void Application::handleScriptEngineLoaded(const QString& scriptFilename) {
qDebug() << "handleScriptEngineLoaded().... scriptFilename:" << scriptFilename;
ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender());
_scriptEnginesHash.insertMulti(scriptFilename, scriptEngine);
@ -4278,18 +4265,9 @@ void Application::handleScriptEngineLoaded(const QString& scriptFilename) {
// register our application services and set it off on its own thread
registerScriptEngineWithApplicationServices(scriptEngine);
scriptEngine->runInThread();
//FIXME - intentionally attempting to test thread safe call to registerGlobalObject()
qDebug() << "about to attempt to call registerGlobalObject on wrong thread!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
scriptEngine->registerGlobalObject("LODManager2", DependencyManager::get<LODManager>().data());
qDebug() << "about to attempt to call registerFunction on wrong thread!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
scriptEngine->registerFunction("WebWindow2", WebWindowClass::constructor, 1);
qDebug() << "about to attempt to call registerGetterSetter on wrong thread!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
scriptEngine->registerGetterSetter("foo_location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter);
}
// FIXME - change to new version of ScriptCache loading notification
void Application::handleScriptLoadError(const QString& scriptFilename) {
qCDebug(interfaceapp) << "Application::loadScript(), script failed to load...";
QMessageBox::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load.");

View file

@ -49,7 +49,6 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
OctreeRenderer(),
_wantScripts(wantScripts),
_entitiesScriptEngine(NULL),
_sandboxScriptEngine(NULL),
_lastMouseEventValid(false),
_viewState(viewState),
_scriptingServices(scriptingServices),
@ -77,15 +76,6 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
EntityTreeRenderer::~EntityTreeRenderer() {
// NOTE: we don't need to delete _entitiesScriptEngine because it is registered with the application and has a
// signal tied to call it's deleteLater on doneRunning
if (_sandboxScriptEngine) {
// TODO: consider reworking how _sandboxScriptEngine is managed. It's treated differently than _entitiesScriptEngine
// because we don't call registerScriptEngineWithApplicationServices() for it. This implementation is confusing and
// potentially error prone because it's not a full fledged ScriptEngine that has been fully connected to the
// application. We did this so that scripts that were ill-formed could be evaluated but not execute against the
// application services. But this means it's shutdown behavior is different from other ScriptEngines
delete _sandboxScriptEngine;
_sandboxScriptEngine = NULL;
}
}
void EntityTreeRenderer::clear() {
@ -115,13 +105,9 @@ void EntityTreeRenderer::init() {
if (_wantScripts) {
_entitiesScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities",
_scriptingServices->getControllerScriptingInterface(), false);
_scriptingServices->getControllerScriptingInterface());
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
// FIXME - this is dubious need to rework
_entitiesScriptEngine->runInThread();
_sandboxScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities Sandbox", NULL, false);
}
// make sure our "last avatar position" is something other than our current position, so that on our
@ -780,7 +766,7 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
}
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
//checkAndCallPreload(entityID);
checkAndCallPreload(entityID);
auto entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
if (entity) {
addEntityToScene(entity);
@ -808,7 +794,9 @@ void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID, const
void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const bool reload) {
if (_tree && !_shuttingDown) {
EntityItemPointer entity = getTree()->findEntityByEntityItemID(entityID);
_entitiesScriptEngine->loadEntityScript(entityID, entity->getScript(), reload);
if (!entity->getScript().isEmpty()) {
_entitiesScriptEngine->loadEntityScript(entityID, entity->getScript(), reload);
}
}
}

View file

@ -143,14 +143,6 @@ private:
bool _wantScripts;
ScriptEngine* _entitiesScriptEngine;
ScriptEngine* _sandboxScriptEngine;
QScriptValue loadEntityScript(EntityItemPointer entity, bool isPreload = false, bool reload = false);
QScriptValue loadEntityScript(const EntityItemID& entityItemID, bool isPreload = false, bool reload = false);
QScriptValue getPreviouslyLoadedEntityScript(const EntityItemID& entityItemID);
QString loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL, bool& isPending, QUrl& url, bool& reload);
//QHash<EntityItemID, EntityScriptDetails> _entityScripts;
void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision);

View file

@ -15,6 +15,7 @@
#include <QNetworkConfiguration>
#include <QNetworkReply>
#include <QObject>
#include <QThread>
#include <assert.h>
#include <SharedUtil.h>
@ -42,7 +43,7 @@ QString ScriptCache::getScript(const QUrl& unnormalizedURL, ScriptUser* scriptUs
if (alreadyWaiting) {
qCDebug(scriptengine) << "Already downloading script at:" << url.toString();
} else {
auto request = ResourceManager::createResourceRequest(this, url);
auto request = ResourceManager::createResourceRequest(nullptr, url);
request->setCacheEnabled(!reload);
connect(request, &ResourceRequest::finished, this, &ScriptCache::scriptDownloaded);
request->send();
@ -82,6 +83,9 @@ void ScriptCache::scriptDownloaded() {
}
void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailableCallback contentAvailable, bool forceDownload) {
#ifdef THREAD_DEBUGGING
qCDebug(scriptengine) << "ScriptCache::getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
#endif
QUrl unnormalizedURL(scriptOrURL);
QUrl url = ResourceManager::normalizeURL(unnormalizedURL);
@ -93,6 +97,9 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable
if (_scriptCache.contains(url) && !forceDownload) {
qCDebug(scriptengine) << "Found script in cache:" << url.toString();
#if 1 // def THREAD_DEBUGGING
qCDebug(scriptengine) << "ScriptCache::getScriptContents() about to call contentAvailable() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
#endif
contentAvailable(url.toString(), _scriptCache[url], true, true);
} else {
bool alreadyWaiting = _contentCallbacks.contains(url);
@ -101,7 +108,10 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable
if (alreadyWaiting) {
qCDebug(scriptengine) << "Already downloading script at:" << url.toString();
} else {
auto request = ResourceManager::createResourceRequest(this, url);
#ifdef THREAD_DEBUGGING
qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
#endif
auto request = ResourceManager::createResourceRequest(nullptr, url);
request->setCacheEnabled(!forceDownload);
connect(request, &ResourceRequest::finished, this, &ScriptCache::scriptContentAvailable);
request->send();
@ -110,6 +120,9 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable
}
void ScriptCache::scriptContentAvailable() {
#ifdef THREAD_DEBUGGING
qCDebug(scriptengine) << "ScriptCache::scriptContentAvailable() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
#endif
ResourceRequest* req = qobject_cast<ResourceRequest*>(sender());
QUrl url = req->getUrl();
QList<contentAvailableCallback> allCallbacks = _contentCallbacks.values(url);

View file

@ -222,7 +222,7 @@ QString ScriptEngine::getFilename() const {
}
// FIXME - remove the file/url scheme code here and let the script cache handle things
// FIXME - switch this to the new model of ScriptCache callbacks
void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
if (_isRunning) {
return;
@ -238,6 +238,7 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
scriptCache->getScript(url, this, isPending, reload);
}
// FIXME - switch this to the new model of ScriptCache callbacks
void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scriptContents) {
_scriptContents = scriptContents;
if (_wantSignals) {
@ -245,6 +246,7 @@ void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scrip
}
}
// FIXME - switch this to the new model of ScriptCache callbacks
void ScriptEngine::errorInLoadingScript(const QUrl& url) {
qCDebug(scriptengine) << "ERROR Loading file:" << url.toString() << "line:" << __LINE__;
if (_wantSignals) {
@ -320,13 +322,17 @@ void ScriptEngine::init() {
void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
#endif
QMetaObject::invokeMethod(this, "registerGlobalObject",
Q_ARG(const QString&, name),
Q_ARG(QObject*, object));
return;
}
//qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
#endif
if (object) {
QScriptValue value = newQObject(object);
@ -336,14 +342,18 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
#endif
QMetaObject::invokeMethod(this, "registerFunction",
Q_ARG(const QString&, name),
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
Q_ARG(int, numArguments));
return;
}
//qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;
#endif
QScriptValue scriptFun = newFunction(functionSignature, numArguments);
globalObject().setProperty(name, scriptFun);
@ -351,14 +361,18 @@ void ScriptEngine::registerFunction(const QString& name, QScriptEngine::Function
void ScriptEngine::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name;
#endif
QMetaObject::invokeMethod(this, "registerFunction",
Q_ARG(const QString&, name),
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
Q_ARG(int, numArguments));
return;
}
//qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;
#endif
QScriptValue object = globalObject().property(parent);
if (object.isValid()) {
@ -370,8 +384,10 @@ void ScriptEngine::registerFunction(const QString& parent, const QString& name,
void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter,
QScriptEngine::FunctionSignature setter, const QString& parent) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
" name:" << name << "parent:" << parent;
#endif
QMetaObject::invokeMethod(this, "registerGetterSetter",
Q_ARG(const QString&, name),
Q_ARG(QScriptEngine::FunctionSignature, getter),
@ -379,7 +395,9 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func
Q_ARG(const QString&, parent));
return;
}
//qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;
#endif
QScriptValue setterFunction = newFunction(setter, 1);
QScriptValue getterFunction = newFunction(getter);
@ -399,15 +417,19 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func
// Unregister the handlers for this eventName and entityID.
void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID << " eventName:" << eventName;
#endif
QMetaObject::invokeMethod(this, "removeEventHandler",
Q_ARG(const EntityItemID&, entityID),
Q_ARG(const QString&, eventName),
Q_ARG(QScriptValue, handler));
return;
}
//qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
#endif
if (!_registeredHandlers.contains(entityID)) {
return;
@ -425,15 +447,20 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin
// Register the handler.
void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID << " eventName:" << eventName;
#endif
QMetaObject::invokeMethod(this, "addEventHandler",
Q_ARG(const EntityItemID&, entityID),
Q_ARG(const QString&, eventName),
Q_ARG(QScriptValue, handler));
return;
}
//qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
#endif
if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script...
// Connect up ALL the handlers to the global entities object's signals.
@ -496,8 +523,10 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN
if (QThread::currentThread() != thread()) {
QScriptValue result;
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"program:" << program << " fileName:" << fileName << "lineNumber:" << lineNumber;
#endif
QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QScriptValue, result),
Q_ARG(const QString&, program),
@ -854,10 +883,10 @@ void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& e
// for the download
void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID <<
"entityScript:" << entityScript <<
"forceRedownload:" << forceRedownload;
"entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload;
#endif
QMetaObject::invokeMethod(this, "loadEntityScript",
Q_ARG(const EntityItemID&, entityID),
@ -865,71 +894,104 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString&
Q_ARG(bool, forceRedownload));
return;
}
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] "
"entityID:" << entityID <<
"entityScript:" << entityScript <<
"forceRedownload:" << forceRedownload;
"entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload;
#endif
// If we've been called our known entityScripts should not know about us..
assert(!_entityScripts.contains(entityID));
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
#endif
DependencyManager::get<ScriptCache>()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
#endif
this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);
}, forceRedownload);
}
// since all of these operations can be asynch we will always do the actual work in the response handler
// for the download
void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success;
#endif
QMetaObject::invokeMethod(this, "entityScriptContentAvailable",
Q_ARG(const EntityItemID&, entityID),
Q_ARG(const QString&, scriptOrURL),
Q_ARG(const QString&, contents),
Q_ARG(bool, isURL),
Q_ARG(bool, success));
return;
}
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
#endif
auto scriptCache = DependencyManager::get<ScriptCache>();
scriptCache->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {
// first check the syntax of the script contents
QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax(contents);
if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID;
qCDebug(scriptengine) << " " << syntaxCheck.errorMessage() << ":"
// first check the syntax of the script contents
QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax(contents);
if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID;
qCDebug(scriptengine) << " " << syntaxCheck.errorMessage() << ":"
<< syntaxCheck.errorLineNumber() << syntaxCheck.errorColumnNumber();
qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL;
scriptCache->addScriptToBadScriptList(scriptOrURL);
return; // done processing script
}
qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL;
scriptCache->addScriptToBadScriptList(scriptOrURL);
return; // done processing script
}
if (isURL) {
setParentURL(scriptOrURL);
}
if (isURL) {
setParentURL(scriptOrURL);
}
QScriptEngine sandbox;
QScriptValue testConstructor = sandbox.evaluate(contents);
QScriptEngine sandbox;
QScriptValue testConstructor = sandbox.evaluate(contents);
if (!testConstructor.isFunction()) {
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID;
qCDebug(scriptengine) << " NOT CONSTRUCTOR";
qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL;
scriptCache->addScriptToBadScriptList(scriptOrURL);
return; // done processing script
}
if (!testConstructor.isFunction()) {
qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID;
qCDebug(scriptengine) << " NOT CONSTRUCTOR";
qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL;
scriptCache->addScriptToBadScriptList(scriptOrURL);
return; // done processing script
}
QScriptValue entityScriptConstructor = evaluate(contents);
QScriptValue entityScriptConstructor = evaluate(contents);
QScriptValue entityScriptObject = entityScriptConstructor.construct();
EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject };
_entityScripts[entityID] = newDetails;
QScriptValue entityScriptObject = entityScriptConstructor.construct();
EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject };
_entityScripts[entityID] = newDetails;
if (isURL) {
setParentURL("");
}
if (isURL) {
setParentURL("");
}
// if we got this far, then call the preload method
callEntityScriptMethod(entityID, "preload");
}, forceRedownload);
// if we got this far, then call the preload method
callEntityScriptMethod(entityID, "preload");
}
void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID;
#endif
QMetaObject::invokeMethod(this, "unloadEntityScript",
Q_ARG(const EntityItemID&, entityID));
return;
}
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] "
"entityID:" << entityID;
#endif
if (_entityScripts.contains(entityID)) {
callEntityScriptMethod(entityID, "unload");
@ -939,18 +1001,20 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID <<
"methodName:" << methodName;
"entityID:" << entityID << "methodName:" << methodName;
#endif
QMetaObject::invokeMethod(this, "callEntityScriptMethod",
Q_ARG(const EntityItemID&, entityID),
Q_ARG(const QString&, methodName));
return;
}
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
"entityID:" << entityID <<
"methodName:" << methodName;
"entityID:" << entityID << "methodName:" << methodName;
#endif
if (_entityScripts.contains(entityID)) {
EntityScriptDetails details = _entityScripts[entityID];
@ -960,15 +1024,16 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
args << entityID.toScriptValue(this);
entityScript.property(methodName).call(entityScript, args);
}
}
}
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID <<
"methodName:" << methodName <<
"event: mouseEvent";
"entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
#endif
QMetaObject::invokeMethod(this, "callEntityScriptMethod",
Q_ARG(const EntityItemID&, entityID),
@ -976,10 +1041,10 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
Q_ARG(const MouseEvent&, event));
return;
}
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
"entityID:" << entityID <<
"methodName:" << methodName <<
"event: mouseEvent";
"entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
#endif
if (_entityScripts.contains(entityID)) {
EntityScriptDetails details = _entityScripts[entityID];
@ -996,11 +1061,10 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) {
if (QThread::currentThread() != thread()) {
#ifdef THREAD_DEBUGGING
qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID <<
"methodName:" << methodName <<
"otherID:" << otherID <<
"collision: collision";
"entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
#endif
QMetaObject::invokeMethod(this, "callEntityScriptMethod",
Q_ARG(const EntityItemID&, entityID),
@ -1009,11 +1073,10 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS
Q_ARG(const Collision&, collision));
return;
}
#ifdef THREAD_DEBUGGING
qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
"entityID:" << entityID <<
"methodName:" << methodName <<
"otherID:" << otherID <<
"collision: collision";
"entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
#endif
if (_entityScripts.contains(entityID)) {
EntityScriptDetails details = _entityScripts[entityID];

View file

@ -188,6 +188,7 @@ private:
QHash<EntityItemID, RegisteredEventHandlers> _registeredHandlers;
void generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator);
Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success);
private:
static QSet<ScriptEngine*> _allKnownScriptEngines;