1785 lines · 76.5 KB · C++
RawDownload
            auto context = sandbox.currentContext();            if (context) {                // Guard against infinite loops and non-performant code                context->throwError(QString("Timed out (entity constructors are limited to %1ms)").arg(SANDBOX_TIMEOUT));            }        });        testConstructor = sandbox.evaluate(program);    }     QString exceptionMessage;    if (hadUncaughtExceptions(sandbox, program.fileName(), this, &exceptionMessage)) {        newDetails.status = ERROR_RUNNING_SCRIPT;        newDetails.errorInfo = exceptionMessage;        _entityScripts[entityID] = newDetails;         return;    }     if (!testConstructor.isFunction()) {        QString testConstructorType = QString(testConstructor.toVariant().typeName());        if (testConstructorType == "") {            testConstructorType = "empty";        }        QString testConstructorValue = testConstructor.toString();        const int maxTestConstructorValueSize = 80;        if (testConstructorValue.size() > maxTestConstructorValueSize) {            testConstructorValue = testConstructorValue.mid(0, maxTestConstructorValueSize) + "...";        }        scriptErrorMessage("Error -- ScriptEngine::loadEntityScript() entity:" + entityID.toString()                              + "failed to load entity script -- expected a function, got " + testConstructorType                              + "," + testConstructorValue                              + "," + scriptOrURL);         if (!isFileUrl) {            scriptCache->addScriptToBadScriptList(scriptOrURL);        }         newDetails.status = ERROR_RUNNING_SCRIPT;        newDetails.errorInfo = "Could not find constructor";        _entityScripts[entityID] = newDetails;         return; // done processing script    }     int64_t lastModified = 0;    if (isFileUrl) {        QString file = QUrl(scriptOrURL).toLocalFile();        lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();    }    QScriptValue entityScriptConstructor, entityScriptObject;    QUrl sandboxURL = currentSandboxURL.isEmpty() ? scriptOrURL : currentSandboxURL;    auto initialization = [&]{        entityScriptConstructor = evaluate(contents, fileName);        entityScriptObject = entityScriptConstructor.construct();    };    doWithEnvironment(entityID, sandboxURL, initialization);     newDetails.scriptObject = entityScriptObject;    newDetails.lastModified = lastModified;    newDetails.definingSandboxURL = sandboxURL;    _entityScripts[entityID] = newDetails;     if (isURL) {        setParentURL("");    }     // 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        qCDebug(scriptengine) << "*** 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    qCDebug(scriptengine) << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "]  "        "entityID:" << entityID;#endif     if (_entityScripts.contains(entityID)) {        if (_entityScripts[entityID].status == RUNNING) {            callEntityScriptMethod(entityID, "unload");        }        _entityScripts.remove(entityID);        stopAllTimersForEntityScript(entityID);    }} void ScriptEngine::unloadAllEntityScripts() {    if (QThread::currentThread() != thread()) {#ifdef THREAD_DEBUGGING        qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";#endif         QMetaObject::invokeMethod(this, "unloadAllEntityScripts");        return;    }#ifdef THREAD_DEBUGGING    qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]";#endif    foreach(const EntityItemID& entityID, _entityScripts.keys()) {        if (_entityScripts[entityID].status == RUNNING) {            callEntityScriptMethod(entityID, "unload");        }    }    _entityScripts.clear(); #ifdef DEBUG_ENGINE_STATE    qCDebug(scriptengine) << "---- CURRENT STATE OF ENGINE: --------------------------";    QScriptValueIterator it(globalObject());    while (it.hasNext()) {        it.next();        qCDebug(scriptengine) << it.name() << ":" << it.value().toString();    }    qCDebug(scriptengine) << "--------------------------------------------------------";#endif // DEBUG_ENGINE_STATE} void ScriptEngine::refreshFileScript(const EntityItemID& entityID) {    if (!_entityScripts.contains(entityID)) {        return;    }     static bool recurseGuard = false;    if (recurseGuard) {        return;    }    recurseGuard = true;     EntityScriptDetails details = _entityScripts[entityID];    // Check to see if a file based script needs to be reloaded (easier debugging)    if (details.lastModified > 0) {        QString filePath = QUrl(details.scriptText).toLocalFile();        auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();        if (lastModified > details.lastModified) {            scriptInfoMessage("Reloading modified script " + details.scriptText);             QFile file(filePath);            file.open(QIODevice::ReadOnly);            QString scriptContents = QTextStream(&file).readAll();            this->unloadEntityScript(entityID);            this->entityScriptContentAvailable(entityID, details.scriptText, scriptContents, true, true);            if (!_entityScripts.contains(entityID) || _entityScripts[entityID].status != RUNNING) {                scriptWarningMessage("Reload script " + details.scriptText + " failed");            } else {                details = _entityScripts[entityID];            }        }    }    recurseGuard = false;} // Execute operation in the appropriate context for (the possibly empty) entityID.// Even if entityID is supplied as currentEntityIdentifier, this still documents the source// of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different// global values for different entity scripts).void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation) {    EntityItemID oldIdentifier = currentEntityIdentifier;    QUrl oldSandboxURL = currentSandboxURL;    currentEntityIdentifier = entityID;    currentSandboxURL = sandboxURL; #if DEBUG_CURRENT_ENTITY    QScriptValue oldData = this->globalObject().property("debugEntityID");    this->globalObject().setProperty("debugEntityID", entityID.toScriptValue(this)); // Make the entityID available to javascript as a global.    operation();    this->globalObject().setProperty("debugEntityID", oldData);#else    operation();#endif    hadUncaughtExceptions(*this, _fileNameString, this);     currentEntityIdentifier = oldIdentifier;    currentSandboxURL = oldSandboxURL;}void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args) {    auto operation = [&]() {        function.call(thisObject, args);    };    doWithEnvironment(entityID, sandboxURL, operation);} void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) {    if (QThread::currentThread() != thread()) {#ifdef THREAD_DEBUGGING        qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]  "            "entityID:" << entityID << "methodName:" << methodName;#endif         QMetaObject::invokeMethod(this, "callEntityScriptMethod",                                  Q_ARG(const EntityItemID&, entityID),                                  Q_ARG(const QString&, methodName),                                  Q_ARG(const QStringList&, params));        return;    }#ifdef THREAD_DEBUGGING    qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "]  "        "entityID:" << entityID << "methodName:" << methodName;#endif     refreshFileScript(entityID);    if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) {        EntityScriptDetails details = _entityScripts[entityID];        QScriptValue entityScript = details.scriptObject; // previously loaded        if (entityScript.property(methodName).isFunction()) {            QScriptValueList args;            args << entityID.toScriptValue(this);            args << qScriptValueFromSequence(this, params);            callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);        }     }} void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event) {    if (QThread::currentThread() != thread()) {#ifdef THREAD_DEBUGGING        qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]  "            "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";#endif         QMetaObject::invokeMethod(this, "callEntityScriptMethod",                                  Q_ARG(const EntityItemID&, entityID),                                  Q_ARG(const QString&, methodName),                                  Q_ARG(const PointerEvent&, event));        return;    }#ifdef THREAD_DEBUGGING    qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "]  "        "entityID:" << entityID << "methodName:" << methodName << "event: pointerEvent";#endif     refreshFileScript(entityID);    if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) {        EntityScriptDetails details = _entityScripts[entityID];        QScriptValue entityScript = details.scriptObject; // previously loaded        if (entityScript.property(methodName).isFunction()) {            QScriptValueList args;            args << entityID.toScriptValue(this);            args << event.toScriptValue(this);            callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);        }    }}  void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) {    if (QThread::currentThread() != thread()) {#ifdef THREAD_DEBUGGING        qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]  "            "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";#endif         QMetaObject::invokeMethod(this, "callEntityScriptMethod",                                  Q_ARG(const EntityItemID&, entityID),                                  Q_ARG(const QString&, methodName),                                  Q_ARG(const EntityItemID&, otherID),                                  Q_ARG(const Collision&, collision));        return;    }#ifdef THREAD_DEBUGGING    qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "]  "        "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";#endif        refreshFileScript(entityID);    if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) {        EntityScriptDetails details = _entityScripts[entityID];        QScriptValue entityScript = details.scriptObject; // previously loaded        if (entityScript.property(methodName).isFunction()) {            QScriptValueList args;            args << entityID.toScriptValue(this);            args << otherID.toScriptValue(this);            args << collisionToScriptValue(this, collision);            callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args);        }    }}

Lines 1501–1785 of 1785. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t