Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 686 files). Show all
Unified · Split
| @@ -72,6 +72,8 @@ static const QScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = · 71 unmodified lines | ||
| 72 | 72 | Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) |
| 73 | 73 | int functionSignatureMetaID = qRegisterMetaType<QScriptEngine::FunctionSignature>(); |
| 74 | 74 | |
| 75 | +Q_LOGGING_CATEGORY(scriptengineScript, "hifi.scriptengine.script") | |
| 76 | + | |
| 75 | 77 | static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ |
| 76 | 78 | QString message = ""; |
| 77 | 79 | for (int i = 0; i < context->argumentCount(); i++) { |
| @@ -80,12 +82,14 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ · 2 unmodified lines | ||
| 80 | 82 | } |
| 81 | 83 | message += context->argument(i).toString(); |
| 82 | 84 | } |
| 83 | − qCDebug(scriptengine).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline | |
| 85 | + qCDebug(scriptengineScript).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline | |
| 84 | 86 | |
| 85 | 87 | message = message.replace("\\", "\\\\") |
| 86 | 88 | .replace("\n", "\\n") |
| 87 | 89 | .replace("\r", "\\r") |
| 88 | 90 | .replace("'", "\\'"); |
| 91 | + | |
| 92 | + // FIXME - this approach neeeds revisiting. print() comes here, which ends up doing an evaluate? | |
| 89 | 93 | engine->evaluate("Script.print('" + message + "')"); |
| 90 | 94 | |
| 91 | 95 | return QScriptValue(); |
| @@ -130,20 +134,20 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID) · 38 unmodified lines | ||
| 130 | 134 | return url + " [EntityID:" + entityID + "]"; |
| 131 | 135 | } |
| 132 | 136 | |
| 133 | −static bool hasCorrectSyntax(const QScriptProgram& program) { | |
| 137 | +static bool hasCorrectSyntax(const QScriptProgram& program, ScriptEngine* reportingEngine) { | |
| 134 | 138 | const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); |
| 135 | 139 | if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { |
| 136 | 140 | const auto error = syntaxCheck.errorMessage(); |
| 137 | 141 | const auto line = QString::number(syntaxCheck.errorLineNumber()); |
| 138 | 142 | const auto column = QString::number(syntaxCheck.errorColumnNumber()); |
| 139 | 143 | const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column); |
| 140 | − qCWarning(scriptengine) << qPrintable(message); | |
| 144 | + reportingEngine->scriptErrorMessage(qPrintable(message)); | |
| 141 | 145 | return false; |
| 142 | 146 | } |
| 143 | 147 | return true; |
| 144 | 148 | } |
| 145 | 149 | |
| 146 | −static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) { | |
| 150 | +static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName, ScriptEngine* reportingEngine) { | |
| 147 | 151 | if (engine.hasUncaughtException()) { |
| 148 | 152 | const auto backtrace = engine.uncaughtExceptionBacktrace(); |
| 149 | 153 | const auto exception = engine.uncaughtException().toString(); |
| @@ -155,7 +159,7 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName · 5 unmodified lines | ||
| 155 | 159 | static const auto lineSeparator = "\n "; |
| 156 | 160 | message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); |
| 157 | 161 | } |
| 158 | − qCWarning(scriptengine) << qPrintable(message); | |
| 162 | + reportingEngine->scriptErrorMessage(qPrintable(message)); | |
| 159 | 163 | return true; |
| 160 | 164 | } |
| 161 | 165 | return false; |
| @@ -170,20 +174,20 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 8 unmodified lines | ||
| 170 | 174 | DependencyManager::get<ScriptEngines>()->addScriptEngine(this); |
| 171 | 175 | |
| 172 | 176 | connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { |
| 173 | − hadUncaughtExceptions(*this, _fileNameString); | |
| 177 | + hadUncaughtExceptions(*this, _fileNameString, this); | |
| 174 | 178 | }); |
| 175 | 179 | |
| 176 | 180 | setProcessEventsInterval(MSECS_PER_SECOND); |
| 177 | 181 | } |
| 178 | 182 | |
| 179 | 183 | ScriptEngine::~ScriptEngine() { |
| 180 | − qCDebug(scriptengine) << "Script Engine shutting down:" << getFilename(); | |
| 184 | + scriptInfoMessage("Script Engine shutting down:" + getFilename()); | |
| 181 | 185 | |
| 182 | 186 | auto scriptEngines = DependencyManager::get<ScriptEngines>(); |
| 183 | 187 | if (scriptEngines) { |
| 184 | 188 | scriptEngines->removeScriptEngine(this); |
| 185 | 189 | } else { |
| 186 | − qCWarning(scriptengine) << "Script destroyed after ScriptEngines!"; | |
| 190 | + scriptWarningMessage("Script destroyed after ScriptEngines!"); | |
| 187 | 191 | } |
| 188 | 192 | } |
| 189 | 193 | |
| @@ -274,7 +278,7 @@ void ScriptEngine::runDebuggable() { · 84 unmodified lines | ||
| 274 | 278 | } |
| 275 | 279 | _lastUpdate = now; |
| 276 | 280 | // Debug and clear exceptions |
| 277 | − hadUncaughtExceptions(*this, _fileNameString); | |
| 281 | + hadUncaughtExceptions(*this, _fileNameString, this); | |
| 278 | 282 | }); |
| 279 | 283 | |
| 280 | 284 | timer->start(10); |
| @@ -359,7 +363,7 @@ void ScriptEngine::waitTillDoneRunning() { · 78 unmodified lines | ||
| 359 | 363 | QThread::yieldCurrentThread(); |
| 360 | 364 | } |
| 361 | 365 | |
| 362 | − qCDebug(scriptengine) << "Script Engine has stopped:" << getFilename(); | |
| 366 | + scriptInfoMessage("Script Engine has stopped:" + getFilename()); | |
| 363 | 367 | } |
| 364 | 368 | } |
| 365 | 369 | |
| @@ -398,10 +402,25 @@ void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scrip · 32 unmodified lines | ||
| 398 | 402 | emit scriptLoaded(url.toString()); |
| 399 | 403 | } |
| 400 | 404 | |
| 405 | +void ScriptEngine::scriptErrorMessage(const QString& message) { | |
| 406 | + qCCritical(scriptengine) << message; | |
| 407 | + emit errorMessage(message); | |
| 408 | +} | |
| 409 | + | |
| 410 | +void ScriptEngine::scriptWarningMessage(const QString& message) { | |
| 411 | + qCWarning(scriptengine) << message; | |
| 412 | + emit warningMessage(message); | |
| 413 | +} | |
| 414 | + | |
| 415 | +void ScriptEngine::scriptInfoMessage(const QString& message) { | |
| 416 | + qCInfo(scriptengine) << message; | |
| 417 | + emit infoMessage(message); | |
| 418 | +} | |
| 419 | + | |
| 401 | 420 | // FIXME - switch this to the new model of ScriptCache callbacks |
| 402 | 421 | void ScriptEngine::errorInLoadingScript(const QUrl& url) { |
| 403 | − qCDebug(scriptengine) << "ERROR Loading file:" << url.toString() << "line:" << __LINE__; | |
| 404 | − emit errorLoadingScript(_fileNameString); // ?? | |
| 422 | + scriptErrorMessage("ERROR Loading file:" + url.toString()); | |
| 423 | + emit errorLoadingScript(_fileNameString); | |
| 405 | 424 | } |
| 406 | 425 | |
| 407 | 426 | // Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of |
| @@ -553,7 +572,7 @@ void ScriptEngine::init() { · 145 unmodified lines | ||
| 553 | 572 | void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { |
| 554 | 573 | if (QThread::currentThread() != thread()) { |
| 555 | 574 | #ifdef THREAD_DEBUGGING |
| 556 | − qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; | |
| 575 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; | |
| 557 | 576 | #endif |
| 558 | 577 | QMetaObject::invokeMethod(this, "registerValue", |
| 559 | 578 | Q_ARG(const QString&, valueName), |
| @@ -583,7 +602,7 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { · 23 unmodified lines | ||
| 583 | 602 | void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { |
| 584 | 603 | if (QThread::currentThread() != thread()) { |
| 585 | 604 | #ifdef THREAD_DEBUGGING |
| 586 | − qDebug() << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | |
| 605 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | |
| 587 | 606 | #endif |
| 588 | 607 | QMetaObject::invokeMethod(this, "registerGlobalObject", |
| 589 | 608 | Q_ARG(const QString&, name), |
| @@ -591,7 +610,7 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { · 1 unmodified line | ||
| 591 | 610 | return; |
| 592 | 611 | } |
| 593 | 612 | #ifdef THREAD_DEBUGGING |
| 594 | − qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; | |
| 613 | + qCDebug(scriptengine) << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; | |
| 595 | 614 | #endif |
| 596 | 615 | |
| 597 | 616 | if (!globalObject().property(name).isValid()) { |
| @@ -607,7 +626,7 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { · 9 unmodified lines | ||
| 607 | 626 | void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { |
| 608 | 627 | if (QThread::currentThread() != thread()) { |
| 609 | 628 | #ifdef THREAD_DEBUGGING |
| 610 | − qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | |
| 629 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | |
| 611 | 630 | #endif |
| 612 | 631 | QMetaObject::invokeMethod(this, "registerFunction", |
| 613 | 632 | Q_ARG(const QString&, name), |
| @@ -616,7 +635,7 @@ void ScriptEngine::registerFunction(const QString& name, QScriptEngine::Function · 2 unmodified lines | ||
| 616 | 635 | return; |
| 617 | 636 | } |
| 618 | 637 | #ifdef THREAD_DEBUGGING |
| 619 | − qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; | |
| 638 | + qCDebug(scriptengine) << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; | |
| 620 | 639 | #endif |
| 621 | 640 | |
| 622 | 641 | QScriptValue scriptFun = newFunction(functionSignature, numArguments); |
| @@ -626,7 +645,7 @@ void ScriptEngine::registerFunction(const QString& name, QScriptEngine::Function · 3 unmodified lines | ||
| 626 | 645 | void ScriptEngine::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { |
| 627 | 646 | if (QThread::currentThread() != thread()) { |
| 628 | 647 | #ifdef THREAD_DEBUGGING |
| 629 | − qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; | |
| 648 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; | |
| 630 | 649 | #endif |
| 631 | 650 | QMetaObject::invokeMethod(this, "registerFunction", |
| 632 | 651 | Q_ARG(const QString&, name), |
| @@ -635,7 +654,7 @@ void ScriptEngine::registerFunction(const QString& parent, const QString& name, · 2 unmodified lines | ||
| 635 | 654 | return; |
| 636 | 655 | } |
| 637 | 656 | #ifdef THREAD_DEBUGGING |
| 638 | − qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; | |
| 657 | + qCDebug(scriptengine) << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; | |
| 639 | 658 | #endif |
| 640 | 659 | |
| 641 | 660 | QScriptValue object = globalObject().property(parent); |
| @@ -649,7 +668,7 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 7 unmodified lines | ||
| 649 | 668 | QScriptEngine::FunctionSignature setter, const QString& parent) { |
| 650 | 669 | if (QThread::currentThread() != thread()) { |
| 651 | 670 | #ifdef THREAD_DEBUGGING |
| 652 | − qDebug() << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 671 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 653 | 672 | " name:" << name << "parent:" << parent; |
| 654 | 673 | #endif |
| 655 | 674 | QMetaObject::invokeMethod(this, "registerGetterSetter", |
| @@ -660,7 +679,7 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 4 unmodified lines | ||
| 660 | 679 | return; |
| 661 | 680 | } |
| 662 | 681 | #ifdef THREAD_DEBUGGING |
| 663 | − qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; | |
| 682 | + qCDebug(scriptengine) << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; | |
| 664 | 683 | #endif |
| 665 | 684 | |
| 666 | 685 | QScriptValue setterFunction = newFunction(setter, 1); |
| @@ -682,7 +701,7 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 15 unmodified lines | ||
| 682 | 701 | void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { |
| 683 | 702 | if (QThread::currentThread() != thread()) { |
| 684 | 703 | #ifdef THREAD_DEBUGGING |
| 685 | − qDebug() << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 704 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 686 | 705 | "entityID:" << entityID << " eventName:" << eventName; |
| 687 | 706 | #endif |
| 688 | 707 | QMetaObject::invokeMethod(this, "removeEventHandler", |
| @@ -692,7 +711,7 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin · 3 unmodified lines | ||
| 692 | 711 | return; |
| 693 | 712 | } |
| 694 | 713 | #ifdef THREAD_DEBUGGING |
| 695 | − qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; | |
| 714 | + qCDebug(scriptengine) << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; | |
| 696 | 715 | #endif |
| 697 | 716 | |
| 698 | 717 | if (!_registeredHandlers.contains(entityID)) { |
| @@ -712,7 +731,7 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin · 13 unmodified lines | ||
| 712 | 731 | void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { |
| 713 | 732 | if (QThread::currentThread() != thread()) { |
| 714 | 733 | #ifdef THREAD_DEBUGGING |
| 715 | − qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 734 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 716 | 735 | "entityID:" << entityID << " eventName:" << eventName; |
| 717 | 736 | #endif |
| 718 | 737 | |
| @@ -723,7 +742,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 4 unmodified lines | ||
| 723 | 742 | return; |
| 724 | 743 | } |
| 725 | 744 | #ifdef THREAD_DEBUGGING |
| 726 | − qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; | |
| 745 | + qCDebug(scriptengine) << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; | |
| 727 | 746 | #endif |
| 728 | 747 | |
| 729 | 748 | if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script... |
| @@ -785,7 +804,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 55 unmodified lines | ||
| 785 | 804 | _registeredHandlers[entityID] = RegisteredEventHandlers(); |
| 786 | 805 | } |
| 787 | 806 | CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName]; |
| 788 | − CallbackData handlerData = {handler, currentEntityIdentifier, currentSandboxURL}; | |
| 807 | + CallbackData handlerData = { handler, currentEntityIdentifier, currentSandboxURL }; | |
| 789 | 808 | handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler(). |
| 790 | 809 | } |
| 791 | 810 | |
| @@ -798,7 +817,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 6 unmodified lines | ||
| 798 | 817 | if (QThread::currentThread() != thread()) { |
| 799 | 818 | QScriptValue result; |
| 800 | 819 | #ifdef THREAD_DEBUGGING |
| 801 | − qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 820 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 802 | 821 | "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; |
| 803 | 822 | #endif |
| 804 | 823 | QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection, |
| @@ -811,7 +830,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 6 unmodified lines | ||
| 811 | 830 | |
| 812 | 831 | // Check syntax |
| 813 | 832 | const QScriptProgram program(sourceCode, fileName, lineNumber); |
| 814 | − if (!hasCorrectSyntax(program)) { | |
| 833 | + if (!hasCorrectSyntax(program, this)) { | |
| 815 | 834 | return QScriptValue(); |
| 816 | 835 | } |
| 817 | 836 | |
| @@ -819,7 +838,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 1 unmodified line | ||
| 819 | 838 | const auto result = QScriptEngine::evaluate(program); |
| 820 | 839 | --_evaluatesPending; |
| 821 | 840 | |
| 822 | − const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName()); | |
| 841 | + const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName(), this); | |
| 823 | 842 | emit evaluationFinished(result, hadUncaughtException); |
| 824 | 843 | return result; |
| 825 | 844 | } |
| @@ -863,23 +882,48 @@ void ScriptEngine::run() { · 37 unmodified lines | ||
| 863 | 882 | // Throttle to SCRIPT_FPS |
| 864 | 883 | // We'd like to try to keep the script at a solid SCRIPT_FPS update rate. And so we will |
| 865 | 884 | // calculate a sleepUntil to be the time from our start time until the original target |
| 866 | − // sleepUntil for this frame. | |
| 867 | − const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); | |
| 868 | − clock::time_point targetSleepUntil(startTime + thisFrame++ * FRAME_DURATION); | |
| 869 | − | |
| 870 | − // However, if our sleepUntil is not at least our average update time into the future | |
| 871 | − // it means our script is taking too long in it's updates, and we want to punish the | |
| 872 | − // script a little bit. So we will force the sleepUntil to be at least our averageUpdate | |
| 873 | − // time into the future. | |
| 885 | + // sleepUntil for this frame. This approach will allow us to "catch up" in the event | |
| 886 | + // that some of our script udpates/frames take a little bit longer than the target average | |
| 887 | + // to execute. | |
| 888 | + // NOTE: if we go to variable SCRIPT_FPS, then we will need to reconsider this approach | |
| 889 | + const std::chrono::microseconds TARGET_SCRIPT_FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); | |
| 890 | + clock::time_point targetSleepUntil(startTime + (thisFrame++ * TARGET_SCRIPT_FRAME_DURATION)); | |
| 891 | + | |
| 892 | + // However, if our sleepUntil is not at least our average update and timer execution time | |
| 893 | + // into the future it means our script is taking too long in its updates, and we want to | |
| 894 | + // punish the script a little bit. So we will force the sleepUntil to be at least our | |
| 895 | + // averageUpdate + averageTimerPerFrame time into the future. | |
| 874 | 896 | auto averageUpdate = totalUpdates / thisFrame; |
| 875 | − auto sleepUntil = std::max(targetSleepUntil, beforeSleep + averageUpdate); | |
| 897 | + auto averageTimerPerFrame = _totalTimerExecution / thisFrame; | |
| 898 | + auto averageTimerAndUpdate = averageUpdate + averageTimerPerFrame; | |
| 899 | + auto sleepUntil = std::max(targetSleepUntil, beforeSleep + averageTimerAndUpdate); | |
| 876 | 900 | |
| 877 | 901 | // We don't want to actually sleep for too long, because it causes our scripts to hang |
| 878 | 902 | // on shutdown and stop... so we want to loop and sleep until we've spent our time in |
| 879 | 903 | // purgatory, constantly checking to see if our script was asked to end |
| 904 | + bool processedEvents = false; | |
| 880 | 905 | while (!_isFinished && clock::now() < sleepUntil) { |
| 906 | + | |
| 881 | 907 | QCoreApplication::processEvents(); // before we sleep again, give events a chance to process |
| 882 | − auto thisSleepUntil = std::min(sleepUntil, clock::now() + FRAME_DURATION); | |
| 908 | + processedEvents = true; | |
| 909 | + | |
| 910 | + // If after processing events, we're past due, exit asap | |
| 911 | + if (clock::now() >= sleepUntil) { | |
| 912 | + break; | |
| 913 | + } | |
| 914 | + | |
| 915 | + // determine how long before the next timer should fire, we'd ideally like to sleep just | |
| 916 | + // that long, so the next processEvents() will allow the timers to fire on time. | |
| 917 | + const std::chrono::microseconds minTimerTimeRemaining(USECS_PER_MSEC * getTimersRemainingTime()); | |
| 918 | + | |
| 919 | + // However, if we haven't yet slept at least as long as our average timer per frame, then we will | |
| 920 | + // punish the timers to at least wait as long as the average run time of the timers. | |
| 921 | + auto untilTimer = std::max(minTimerTimeRemaining, averageTimerPerFrame); | |
| 922 | + | |
| 923 | + // choose the closest time point, our | |
| 924 | + auto remainingSleepUntil = std::chrono::duration_cast<std::chrono::microseconds>(sleepUntil - clock::now()); | |
| 925 | + auto closestUntil = std::min(remainingSleepUntil, untilTimer); | |
| 926 | + auto thisSleepUntil = std::min(sleepUntil, clock::now() + closestUntil); | |
| 883 | 927 | std::this_thread::sleep_until(thisSleepUntil); |
| 884 | 928 | } |
| 885 | 929 | |
| @@ -904,7 +948,10 @@ void ScriptEngine::run() { · 18 unmodified lines | ||
| 904 | 948 | break; |
| 905 | 949 | } |
| 906 | 950 | |
| 907 | − QCoreApplication::processEvents(); | |
| 951 | + // Only call this if we didn't processEvents as part of waiting for next frame | |
| 952 | + if (!processedEvents) { | |
| 953 | + QCoreApplication::processEvents(); | |
| 954 | + } | |
| 908 | 955 | |
| 909 | 956 | if (_isFinished) { |
| 910 | 957 | break; |
| @@ -936,10 +983,10 @@ void ScriptEngine::run() { · 25 unmodified lines | ||
| 936 | 983 | _lastUpdate = now; |
| 937 | 984 | |
| 938 | 985 | // Debug and clear exceptions |
| 939 | − hadUncaughtExceptions(*this, _fileNameString); | |
| 986 | + hadUncaughtExceptions(*this, _fileNameString, this); | |
| 940 | 987 | } |
| 941 | 988 | |
| 942 | − qCDebug(scriptengine) << "Script Engine stopping:" << getFilename(); | |
| 989 | + scriptInfoMessage("Script Engine stopping:" + getFilename()); | |
| 943 | 990 | |
| 944 | 991 | stopAllTimers(); // make sure all our timers are stopped if the script is ending |
| 945 | 992 | emit scriptEnding(); |
| @@ -967,6 +1014,21 @@ void ScriptEngine::run() { · 21 unmodified lines | ||
| 967 | 1014 | emit doneRunning(); |
| 968 | 1015 | } |
| 969 | 1016 | |
| 1017 | +quint64 ScriptEngine::getTimersRemainingTime() { | |
| 1018 | + quint64 minimumTime = USECS_PER_SECOND; // anything larger than this can be ignored | |
| 1019 | + QMutableHashIterator<QTimer*, CallbackData> i(_timerFunctionMap); | |
| 1020 | + while (i.hasNext()) { | |
| 1021 | + i.next(); | |
| 1022 | + QTimer* timer = i.key(); | |
| 1023 | + int remainingTime = timer->remainingTime(); | |
| 1024 | + if (remainingTime >= 0) { | |
| 1025 | + minimumTime = std::min((quint64)remainingTime, minimumTime); | |
| 1026 | + } | |
| 1027 | + } | |
| 1028 | + return minimumTime; | |
| 1029 | +} | |
| 1030 | + | |
| 1031 | + | |
| 970 | 1032 | // NOTE: This is private because it must be called on the same thread that created the timers, which is why |
| 971 | 1033 | // we want to only call it in our own run "shutdown" processing. |
| 972 | 1034 | void ScriptEngine::stopAllTimers() { |
| @@ -1012,7 +1074,7 @@ void ScriptEngine::stop(bool marshal) { · 39 unmodified lines | ||
| 1012 | 1074 | void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) { |
| 1013 | 1075 | if (QThread::currentThread() != thread()) { |
| 1014 | 1076 | #ifdef THREAD_DEBUGGING |
| 1015 | − qDebug() << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | |
| 1077 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | |
| 1016 | 1078 | #endif |
| 1017 | 1079 | QMetaObject::invokeMethod(this, "callAnimationStateHandler", |
| 1018 | 1080 | Q_ARG(QScriptValue, callback), |
| @@ -1046,7 +1108,7 @@ void ScriptEngine::timerFired() { · 27 unmodified lines | ||
| 1046 | 1108 | { |
| 1047 | 1109 | auto engine = DependencyManager::get<ScriptEngines>(); |
| 1048 | 1110 | if (!engine || engine->isStopped()) { |
| 1049 | − qCDebug(scriptengine) << "Script.timerFired() while shutting down is ignored... parent script:" << getFilename(); | |
| 1111 | + scriptWarningMessage("Script.timerFired() while shutting down is ignored... parent script:" + getFilename()); | |
| 1050 | 1112 | return; // bail early |
| 1051 | 1113 | } |
| 1052 | 1114 | } |
| @@ -1062,7 +1124,12 @@ void ScriptEngine::timerFired() { · 9 unmodified lines | ||
| 1062 | 1124 | |
| 1063 | 1125 | // call the associated JS function, if it exists |
| 1064 | 1126 | if (timerData.function.isValid()) { |
| 1127 | + auto preTimer = p_high_resolution_clock::now(); | |
| 1065 | 1128 | callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList()); |
| 1129 | + auto postTimer = p_high_resolution_clock::now(); | |
| 1130 | + auto elapsed = (postTimer - preTimer); | |
| 1131 | + _totalTimerExecution += std::chrono::duration_cast<std::chrono::microseconds>(elapsed); | |
| 1132 | + | |
| 1066 | 1133 | } |
| 1067 | 1134 | } |
| 1068 | 1135 | |
| @@ -1072,12 +1139,18 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 3 unmodified lines | ||
| 1072 | 1139 | QTimer* newTimer = new QTimer(this); |
| 1073 | 1140 | newTimer->setSingleShot(isSingleShot); |
| 1074 | 1141 | |
| 1142 | + // The default timer type is not very accurate below about 200ms http://doc.qt.io/qt-5/qt.html#TimerType-enum | |
| 1143 | + static const int MIN_TIMEOUT_FOR_COARSE_TIMER = 200; | |
| 1144 | + if (intervalMS < MIN_TIMEOUT_FOR_COARSE_TIMER) { | |
| 1145 | + newTimer->setTimerType(Qt::PreciseTimer); | |
| 1146 | + } | |
| 1147 | + | |
| 1075 | 1148 | connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); |
| 1076 | 1149 | |
| 1077 | 1150 | // make sure the timer stops when the script does |
| 1078 | 1151 | connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); |
| 1079 | 1152 | |
| 1080 | − CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL}; | |
| 1153 | + CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL }; | |
| 1081 | 1154 | _timerFunctionMap.insert(newTimer, timerData); |
| 1082 | 1155 | |
| 1083 | 1156 | newTimer->start(intervalMS); |
| @@ -1086,7 +1159,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 2 unmodified lines | ||
| 1086 | 1159 | |
| 1087 | 1160 | QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) { |
| 1088 | 1161 | if (DependencyManager::get<ScriptEngines>()->isStopped()) { |
| 1089 | − qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename(); | |
| 1162 | + scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename()); | |
| 1090 | 1163 | return NULL; // bail early |
| 1091 | 1164 | } |
| 1092 | 1165 | |
| @@ -1095,7 +1168,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) · 2 unmodified lines | ||
| 1095 | 1168 | |
| 1096 | 1169 | QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { |
| 1097 | 1170 | if (DependencyManager::get<ScriptEngines>()->isStopped()) { |
| 1098 | − qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename(); | |
| 1171 | + scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename()); | |
| 1099 | 1172 | return NULL; // bail early |
| 1100 | 1173 | } |
| 1101 | 1174 | |
| @@ -1155,8 +1228,8 @@ void ScriptEngine::print(const QString& message) { · 53 unmodified lines | ||
| 1155 | 1228 | // all of the files have finished loading. |
| 1156 | 1229 | void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) { |
| 1157 | 1230 | if (DependencyManager::get<ScriptEngines>()->isStopped()) { |
| 1158 | − qCDebug(scriptengine) << "Script.include() while shutting down is ignored..." | |
| 1159 | − << "includeFiles:" << includeFiles << "parent script:" << getFilename(); | |
| 1231 | + scriptWarningMessage("Script.include() while shutting down is ignored... includeFiles:" | |
| 1232 | + + includeFiles.join(",") + "parent script:" + getFilename()); | |
| 1160 | 1233 | return; // bail early |
| 1161 | 1234 | } |
| 1162 | 1235 | QList<QUrl> urls; |
| @@ -1176,14 +1249,15 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 13 unmodified lines | ||
| 1176 | 1249 | // Guard against meaningless query and fragment parts. |
| 1177 | 1250 | // Do NOT use PreferLocalFile as its behavior is unpredictable (e.g., on defaultScriptsLocation()) |
| 1178 | 1251 | const auto strippingFlags = QUrl::RemoveFilename | QUrl::RemoveQuery | QUrl::RemoveFragment; |
| 1179 | − for (QString file : includeFiles) { | |
| 1252 | + for (QString includeFile : includeFiles) { | |
| 1253 | + QString file = ResourceManager::normalizeURL(includeFile); | |
| 1180 | 1254 | QUrl thisURL; |
| 1181 | 1255 | bool isStandardLibrary = false; |
| 1182 | 1256 | if (file.startsWith("/~/")) { |
| 1183 | 1257 | thisURL = expandScriptUrl(QUrl::fromLocalFile(expandScriptPath(file))); |
| 1184 | 1258 | QUrl defaultScriptsLoc = defaultScriptsLocation(); |
| 1185 | 1259 | if (!defaultScriptsLoc.isParentOf(thisURL)) { |
| 1186 | − qDebug() << "ScriptEngine::include -- skipping" << file << "-- outside of standard libraries"; | |
| 1260 | + scriptWarningMessage("Script.include() -- skipping" + file + "-- outside of standard libraries"); | |
| 1187 | 1261 | continue; |
| 1188 | 1262 | } |
| 1189 | 1263 | isStandardLibrary = true; |
| @@ -1191,20 +1265,16 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 1 unmodified line | ||
| 1191 | 1265 | thisURL = resolvePath(file); |
| 1192 | 1266 | } |
| 1193 | 1267 | |
| 1194 | − if (!_includedURLs.contains(thisURL)) { | |
| 1195 | − if (!isStandardLibrary && !currentSandboxURL.isEmpty() && (thisURL.scheme() == "file") && | |
| 1196 | − (currentSandboxURL.scheme() != "file" || | |
| 1197 | − !thisURL.toString(strippingFlags).startsWith(currentSandboxURL.toString(strippingFlags), getSensitivity()))) { | |
| 1198 | − qCWarning(scriptengine) << "Script.include() ignoring file path" | |
| 1199 | − << thisURL << "outside of original entity script" << currentSandboxURL; | |
| 1200 | − } else { | |
| 1201 | − // We could also check here for CORS, but we don't yet. | |
| 1202 | − // It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here. | |
| 1203 | − urls.append(thisURL); | |
| 1204 | − _includedURLs << thisURL; | |
| 1205 | − } | |
| 1268 | + if (!isStandardLibrary && !currentSandboxURL.isEmpty() && (thisURL.scheme() == "file") && | |
| 1269 | + (currentSandboxURL.scheme() != "file" || | |
| 1270 | + !thisURL.toString(strippingFlags).startsWith(currentSandboxURL.toString(strippingFlags), getSensitivity()))) { | |
| 1271 | + | |
| 1272 | + scriptWarningMessage("Script.include() ignoring file path" + thisURL.toString() | |
| 1273 | + + "outside of original entity script" + currentSandboxURL.toString()); | |
| 1206 | 1274 | } else { |
| 1207 | − qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL; | |
| 1275 | + // We could also check here for CORS, but we don't yet. | |
| 1276 | + // It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here. | |
| 1277 | + urls.append(thisURL); | |
| 1208 | 1278 | } |
| 1209 | 1279 | } |
| 1210 | 1280 | |
| @@ -1222,15 +1292,22 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 11 unmodified lines | ||
| 1222 | 1292 | for (QUrl url : urls) { |
| 1223 | 1293 | QString contents = data[url]; |
| 1224 | 1294 | if (contents.isNull()) { |
| 1225 | − qCDebug(scriptengine) << "Error loading file: " << url << "line:" << __LINE__; | |
| 1295 | + scriptErrorMessage("Error loading file: " + url.toString()); | |
| 1226 | 1296 | } else { |
| 1227 | − // Set the parent url so that path resolution will be relative | |
| 1228 | − // to this script's url during its initial evaluation | |
| 1229 | − _parentURL = url.toString(); | |
| 1230 | − auto operation = [&]() { | |
| 1231 | − evaluate(contents, url.toString()); | |
| 1232 | − }; | |
| 1233 | − doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation); | |
| 1297 | + std::lock_guard<std::recursive_mutex> lock(_lock); | |
| 1298 | + if (!_includedURLs.contains(url)) { | |
| 1299 | + _includedURLs << url; | |
| 1300 | + // Set the parent url so that path resolution will be relative | |
| 1301 | + // to this script's url during its initial evaluation | |
| 1302 | + _parentURL = url.toString(); | |
| 1303 | + auto operation = [&]() { | |
| 1304 | + evaluate(contents, url.toString()); | |
| 1305 | + }; | |
| 1306 | + | |
| 1307 | + doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation); | |
| 1308 | + } else { | |
| 1309 | + scriptWarningMessage("Script.include() skipping evaluation of previously included url:" + url.toString()); | |
| 1310 | + } | |
| 1234 | 1311 | } |
| 1235 | 1312 | } |
| 1236 | 1313 | _parentURL = parentURL; |
| @@ -1258,8 +1335,8 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 21 unmodified lines | ||
| 1258 | 1335 | |
| 1259 | 1336 | void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { |
| 1260 | 1337 | if (DependencyManager::get<ScriptEngines>()->isStopped()) { |
| 1261 | − qCDebug(scriptengine) << "Script.include() while shutting down is ignored... " | |
| 1262 | − << "includeFile:" << includeFile << "parent script:" << getFilename(); | |
| 1338 | + scriptWarningMessage("Script.include() while shutting down is ignored... includeFile:" | |
| 1339 | + + includeFile + "parent script:" + getFilename()); | |
| 1263 | 1340 | return; // bail early |
| 1264 | 1341 | } |
| 1265 | 1342 | |
| @@ -1273,13 +1350,13 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { · 7 unmodified lines | ||
| 1273 | 1350 | // the Application or other context will connect to in order to know to actually load the script |
| 1274 | 1351 | void ScriptEngine::load(const QString& loadFile) { |
| 1275 | 1352 | if (DependencyManager::get<ScriptEngines>()->isStopped()) { |
| 1276 | − qCDebug(scriptengine) << "Script.load() while shutting down is ignored... " | |
| 1277 | − << "loadFile:" << loadFile << "parent script:" << getFilename(); | |
| 1353 | + scriptWarningMessage("Script.load() while shutting down is ignored... loadFile:" | |
| 1354 | + + loadFile + "parent script:" + getFilename()); | |
| 1278 | 1355 | return; // bail early |
| 1279 | 1356 | } |
| 1280 | 1357 | if (!currentEntityIdentifier.isInvalidID()) { |
| 1281 | − qCWarning(scriptengine) << "Script.load() from entity script is ignored... " | |
| 1282 | − << "loadFile:" << loadFile << "parent script:" << getFilename(); | |
| 1358 | + scriptWarningMessage("Script.load() from entity script is ignored... loadFile:" | |
| 1359 | + + loadFile + "parent script:" + getFilename()); | |
| 1283 | 1360 | return; // bail early |
| 1284 | 1361 | } |
| 1285 | 1362 | |
| @@ -1296,7 +1373,7 @@ void ScriptEngine::load(const QString& loadFile) { · 10 unmodified lines | ||
| 1296 | 1373 | // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args |
| 1297 | 1374 | void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHandlerArgs) { |
| 1298 | 1375 | if (QThread::currentThread() != thread()) { |
| 1299 | − qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; | |
| 1376 | + qCDebug(scriptengine) << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; | |
| 1300 | 1377 | assert(false); |
| 1301 | 1378 | return ; |
| 1302 | 1379 | } |
| @@ -1330,7 +1407,7 @@ void ScriptEngine::loadEntityScript(QWeakPointer<ScriptEngine> theEngine, const · 27 unmodified lines | ||
| 1330 | 1407 | QSharedPointer<ScriptEngine> strongEngine = theEngine.toStrongRef(); |
| 1331 | 1408 | if (strongEngine) { |
| 1332 | 1409 | #ifdef THREAD_DEBUGGING |
| 1333 | − qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" | |
| 1410 | + qCDebug(scriptengine) << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" | |
| 1334 | 1411 | << QThread::currentThread() << "] expected thread [" << strongEngine->thread() << "]"; |
| 1335 | 1412 | #endif |
| 1336 | 1413 | strongEngine->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success); |
| @@ -1343,7 +1420,7 @@ void ScriptEngine::loadEntityScript(QWeakPointer<ScriptEngine> theEngine, const · 6 unmodified lines | ||
| 1343 | 1420 | void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { |
| 1344 | 1421 | if (QThread::currentThread() != thread()) { |
| 1345 | 1422 | #ifdef THREAD_DEBUGGING |
| 1346 | − qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" | |
| 1423 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" | |
| 1347 | 1424 | << QThread::currentThread() << "], invoking on correct thread [" << thread() |
| 1348 | 1425 | << "] " "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" |
| 1349 | 1426 | << contents << "isURL:" << isURL << "success:" << success; |
| @@ -1359,7 +1436,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 9 unmodified lines | ||
| 1359 | 1436 | } |
| 1360 | 1437 | |
| 1361 | 1438 | #ifdef THREAD_DEBUGGING |
| 1362 | − qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; | |
| 1439 | + qCDebug(scriptengine) << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; | |
| 1363 | 1440 | #endif |
| 1364 | 1441 | |
| 1365 | 1442 | auto scriptCache = DependencyManager::get<ScriptCache>(); |
| @@ -1367,7 +1444,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 1 unmodified line | ||
| 1367 | 1444 | auto fileName = isURL ? scriptOrURL : "EmbeddedEntityScript"; |
| 1368 | 1445 | |
| 1369 | 1446 | QScriptProgram program(contents, fileName); |
| 1370 | − if (!hasCorrectSyntax(program)) { | |
| 1447 | + if (!hasCorrectSyntax(program, this)) { | |
| 1371 | 1448 | if (!isFileUrl) { |
| 1372 | 1449 | scriptCache->addScriptToBadScriptList(scriptOrURL); |
| 1373 | 1450 | } |
| @@ -1395,7 +1472,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 21 unmodified lines | ||
| 1395 | 1472 | }); |
| 1396 | 1473 | testConstructor = sandbox.evaluate(program); |
| 1397 | 1474 | } |
| 1398 | − if (hadUncaughtExceptions(sandbox, program.fileName())) { | |
| 1475 | + if (hadUncaughtExceptions(sandbox, program.fileName(), this)) { | |
| 1399 | 1476 | return; |
| 1400 | 1477 | } |
| 1401 | 1478 | |
| @@ -1409,10 +1486,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 7 unmodified lines | ||
| 1409 | 1486 | if (testConstructorValue.size() > maxTestConstructorValueSize) { |
| 1410 | 1487 | testConstructorValue = testConstructorValue.mid(0, maxTestConstructorValueSize) + "..."; |
| 1411 | 1488 | } |
| 1412 | − qCDebug(scriptengine) << "Error -- ScriptEngine::loadEntityScript() entity:" << entityID | |
| 1413 | − << "failed to load entity script -- expected a function, got " + testConstructorType | |
| 1414 | − << "," << testConstructorValue | |
| 1415 | − << "," << scriptOrURL; | |
| 1489 | + scriptErrorMessage("Error -- ScriptEngine::loadEntityScript() entity:" + entityID.toString() | |
| 1490 | + + "failed to load entity script -- expected a function, got " + testConstructorType | |
| 1491 | + + "," + testConstructorValue | |
| 1492 | + + "," + scriptOrURL); | |
| 1416 | 1493 | |
| 1417 | 1494 | if (!isFileUrl) { |
| 1418 | 1495 | scriptCache->addScriptToBadScriptList(scriptOrURL); |
| @@ -1447,7 +1524,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 28 unmodified lines | ||
| 1447 | 1524 | void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { |
| 1448 | 1525 | if (QThread::currentThread() != thread()) { |
| 1449 | 1526 | #ifdef THREAD_DEBUGGING |
| 1450 | − qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 1527 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 1451 | 1528 | "entityID:" << entityID; |
| 1452 | 1529 | #endif |
| 1453 | 1530 | |
| @@ -1456,7 +1533,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 2 unmodified lines | ||
| 1456 | 1533 | return; |
| 1457 | 1534 | } |
| 1458 | 1535 | #ifdef THREAD_DEBUGGING |
| 1459 | − qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] " | |
| 1536 | + qCDebug(scriptengine) << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] " | |
| 1460 | 1537 | "entityID:" << entityID; |
| 1461 | 1538 | #endif |
| 1462 | 1539 | |
| @@ -1470,14 +1547,14 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 7 unmodified lines | ||
| 1470 | 1547 | void ScriptEngine::unloadAllEntityScripts() { |
| 1471 | 1548 | if (QThread::currentThread() != thread()) { |
| 1472 | 1549 | #ifdef THREAD_DEBUGGING |
| 1473 | − qDebug() << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; | |
| 1550 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; | |
| 1474 | 1551 | #endif |
| 1475 | 1552 | |
| 1476 | 1553 | QMetaObject::invokeMethod(this, "unloadAllEntityScripts"); |
| 1477 | 1554 | return; |
| 1478 | 1555 | } |
| 1479 | 1556 | #ifdef THREAD_DEBUGGING |
| 1480 | − qDebug() << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; | |
| 1557 | + qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; | |
| 1481 | 1558 | #endif |
| 1482 | 1559 | foreach(const EntityItemID& entityID, _entityScripts.keys()) { |
| 1483 | 1560 | callEntityScriptMethod(entityID, "unload"); |
| @@ -1485,13 +1562,13 @@ void ScriptEngine::unloadAllEntityScripts() { · 1 unmodified line | ||
| 1485 | 1562 | _entityScripts.clear(); |
| 1486 | 1563 | |
| 1487 | 1564 | #ifdef DEBUG_ENGINE_STATE |
| 1488 | − qDebug() << "---- CURRENT STATE OF ENGINE: --------------------------"; | |
| 1565 | + qCDebug(scriptengine) << "---- CURRENT STATE OF ENGINE: --------------------------"; | |
| 1489 | 1566 | QScriptValueIterator it(globalObject()); |
| 1490 | 1567 | while (it.hasNext()) { |
| 1491 | 1568 | it.next(); |
| 1492 | − qDebug() << it.name() << ":" << it.value().toString(); | |
| 1569 | + qCDebug(scriptengine) << it.name() << ":" << it.value().toString(); | |
| 1493 | 1570 | } |
| 1494 | − qDebug() << "--------------------------------------------------------"; | |
| 1571 | + qCDebug(scriptengine) << "--------------------------------------------------------"; | |
| 1495 | 1572 | #endif // DEBUG_ENGINE_STATE |
| 1496 | 1573 | } |
| 1497 | 1574 | |
| @@ -1512,7 +1589,7 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 14 unmodified lines | ||
| 1512 | 1589 | QString filePath = QUrl(details.scriptText).toLocalFile(); |
| 1513 | 1590 | auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch(); |
| 1514 | 1591 | if (lastModified > details.lastModified) { |
| 1515 | − qCDebug(scriptengine) << "Reloading modified script " << details.scriptText; | |
| 1592 | + scriptInfoMessage("Reloading modified script " + details.scriptText); | |
| 1516 | 1593 | |
| 1517 | 1594 | QFile file(filePath); |
| 1518 | 1595 | file.open(QIODevice::ReadOnly); |
| @@ -1520,7 +1597,7 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 1 unmodified line | ||
| 1520 | 1597 | this->unloadEntityScript(entityID); |
| 1521 | 1598 | this->entityScriptContentAvailable(entityID, details.scriptText, scriptContents, true, true); |
| 1522 | 1599 | if (!_entityScripts.contains(entityID)) { |
| 1523 | − qWarning() << "Reload script " << details.scriptText << " failed"; | |
| 1600 | + scriptWarningMessage("Reload script " + details.scriptText + " failed"); | |
| 1524 | 1601 | } else { |
| 1525 | 1602 | details = _entityScripts[entityID]; |
| 1526 | 1603 | } |
| @@ -1547,7 +1624,7 @@ void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, const QUrl& s · 20 unmodified lines | ||
| 1547 | 1624 | #else |
| 1548 | 1625 | operation(); |
| 1549 | 1626 | #endif |
| 1550 | − hadUncaughtExceptions(*this, _fileNameString); | |
| 1627 | + hadUncaughtExceptions(*this, _fileNameString, this); | |
| 1551 | 1628 | |
| 1552 | 1629 | currentEntityIdentifier = oldIdentifier; |
| 1553 | 1630 | currentSandboxURL = oldSandboxURL; |
| @@ -1562,7 +1639,7 @@ void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& · 8 unmodified lines | ||
| 1562 | 1639 | void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) { |
| 1563 | 1640 | if (QThread::currentThread() != thread()) { |
| 1564 | 1641 | #ifdef THREAD_DEBUGGING |
| 1565 | − qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 1642 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 1566 | 1643 | "entityID:" << entityID << "methodName:" << methodName; |
| 1567 | 1644 | #endif |
| 1568 | 1645 | |
| @@ -1573,7 +1650,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines | ||
| 1573 | 1650 | return; |
| 1574 | 1651 | } |
| 1575 | 1652 | #ifdef THREAD_DEBUGGING |
| 1576 | − qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " | |
| 1653 | + qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " | |
| 1577 | 1654 | "entityID:" << entityID << "methodName:" << methodName; |
| 1578 | 1655 | #endif |
| 1579 | 1656 | |
| @@ -1594,7 +1671,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 14 unmodified lines | ||
| 1594 | 1671 | void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event) { |
| 1595 | 1672 | if (QThread::currentThread() != thread()) { |
| 1596 | 1673 | #ifdef THREAD_DEBUGGING |
| 1597 | − qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 1674 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 1598 | 1675 | "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; |
| 1599 | 1676 | #endif |
| 1600 | 1677 | |
| @@ -1605,7 +1682,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines | ||
| 1605 | 1682 | return; |
| 1606 | 1683 | } |
| 1607 | 1684 | #ifdef THREAD_DEBUGGING |
| 1608 | − qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " | |
| 1685 | + qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " | |
| 1609 | 1686 | "entityID:" << entityID << "methodName:" << methodName << "event: pointerEvent"; |
| 1610 | 1687 | #endif |
| 1611 | 1688 | |
| @@ -1626,7 +1703,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 14 unmodified lines | ||
| 1626 | 1703 | void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) { |
| 1627 | 1704 | if (QThread::currentThread() != thread()) { |
| 1628 | 1705 | #ifdef THREAD_DEBUGGING |
| 1629 | − qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 1706 | + qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | |
| 1630 | 1707 | "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; |
| 1631 | 1708 | #endif |
| 1632 | 1709 | |
| @@ -1638,7 +1715,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 5 unmodified lines | ||
| 1638 | 1715 | return; |
| 1639 | 1716 | } |
| 1640 | 1717 | #ifdef THREAD_DEBUGGING |
| 1641 | − qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " | |
| 1718 | + qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " | |
| 1642 | 1719 | "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; |
| 1643 | 1720 | #endif |
| 1644 | 1721 | |