History

Merge branch 'master' into tablet-ui

Anthony J. Thibault committed 9 years ago

Commit 00980362 parents 6729421 45c71fd173 files · +5924 −1762Browse files

Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 173 files). Show all

Unified · Split

libraries/script-engine/src/ScriptEngine.cpp+160−86
@@ -71,6 +71,8 @@ static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3" · 70 unmodified lines
71Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)71Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)
72int functionSignatureMetaID = qRegisterMetaType<QScriptEngine::FunctionSignature>();72int functionSignatureMetaID = qRegisterMetaType<QScriptEngine::FunctionSignature>();
73 73
74Q_LOGGING_CATEGORY(scriptengineScript, "hifi.scriptengine.script")
75
74static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){76static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){
75 QString message = "";77 QString message = "";
76 for (int i = 0; i < context->argumentCount(); i++) {78 for (int i = 0; i < context->argumentCount(); i++) {
@@ -79,12 +81,14 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ · 2 unmodified lines
79 }81 }
80 message += context->argument(i).toString();82 message += context->argument(i).toString();
81 }83 }
82 qCDebug(scriptengine).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline84 qCDebug(scriptengineScript).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline
83 85
84 message = message.replace("\\", "\\\\")86 message = message.replace("\\", "\\\\")
85 .replace("\n", "\\n")87 .replace("\n", "\\n")
86 .replace("\r", "\\r")88 .replace("\r", "\\r")
87 .replace("'", "\\'");89 .replace("'", "\\'");
90
91 // FIXME - this approach neeeds revisiting. print() comes here, which ends up doing an evaluate?
88 engine->evaluate("Script.print('" + message + "')");92 engine->evaluate("Script.print('" + message + "')");
89 93
90 return QScriptValue();94 return QScriptValue();
@@ -129,20 +133,20 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID) · 38 unmodified lines
129 return url + " [EntityID:" + entityID + "]";133 return url + " [EntityID:" + entityID + "]";
130}134}
131 135
132static bool hasCorrectSyntax(const QScriptProgram& program) {136static bool hasCorrectSyntax(const QScriptProgram& program, ScriptEngine* reportingEngine) {
133 const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode());137 const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode());
134 if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {138 if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
135 const auto error = syntaxCheck.errorMessage();139 const auto error = syntaxCheck.errorMessage();
136 const auto line = QString::number(syntaxCheck.errorLineNumber());140 const auto line = QString::number(syntaxCheck.errorLineNumber());
137 const auto column = QString::number(syntaxCheck.errorColumnNumber());141 const auto column = QString::number(syntaxCheck.errorColumnNumber());
138 const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column);142 const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column);
139 qCWarning(scriptengine) << qPrintable(message);143 reportingEngine->scriptErrorMessage(qPrintable(message));
140 return false;144 return false;
141 }145 }
142 return true;146 return true;
143}147}
144 148
145static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) {149static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName, ScriptEngine* reportingEngine) {
146 if (engine.hasUncaughtException()) {150 if (engine.hasUncaughtException()) {
147 const auto backtrace = engine.uncaughtExceptionBacktrace();151 const auto backtrace = engine.uncaughtExceptionBacktrace();
148 const auto exception = engine.uncaughtException().toString();152 const auto exception = engine.uncaughtException().toString();
@@ -154,7 +158,7 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName · 5 unmodified lines
154 static const auto lineSeparator = "\n ";158 static const auto lineSeparator = "\n ";
155 message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));159 message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
156 }160 }
157 qCWarning(scriptengine) << qPrintable(message);161 reportingEngine->scriptErrorMessage(qPrintable(message));
158 return true;162 return true;
159 }163 }
160 return false;164 return false;
@@ -169,20 +173,20 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 8 unmodified lines
169 DependencyManager::get<ScriptEngines>()->addScriptEngine(this);173 DependencyManager::get<ScriptEngines>()->addScriptEngine(this);
170 174
171 connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {175 connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {
172 hadUncaughtExceptions(*this, _fileNameString);176 hadUncaughtExceptions(*this, _fileNameString, this);
173 });177 });
174 178
175 setProcessEventsInterval(MSECS_PER_SECOND);179 setProcessEventsInterval(MSECS_PER_SECOND);
176}180}
177 181
178ScriptEngine::~ScriptEngine() {182ScriptEngine::~ScriptEngine() {
179 qCDebug(scriptengine) << "Script Engine shutting down:" << getFilename();183 scriptInfoMessage("Script Engine shutting down:" + getFilename());
180 184
181 auto scriptEngines = DependencyManager::get<ScriptEngines>();185 auto scriptEngines = DependencyManager::get<ScriptEngines>();
182 if (scriptEngines) {186 if (scriptEngines) {
183 scriptEngines->removeScriptEngine(this);187 scriptEngines->removeScriptEngine(this);
184 } else {188 } else {
185 qCWarning(scriptengine) << "Script destroyed after ScriptEngines!";189 scriptWarningMessage("Script destroyed after ScriptEngines!");
186 }190 }
187}191}
188 192
@@ -273,7 +277,7 @@ void ScriptEngine::runDebuggable() { · 84 unmodified lines
273 }277 }
274 _lastUpdate = now;278 _lastUpdate = now;
275 // Debug and clear exceptions279 // Debug and clear exceptions
276 hadUncaughtExceptions(*this, _fileNameString);280 hadUncaughtExceptions(*this, _fileNameString, this);
277 });281 });
278 282
279 timer->start(10);283 timer->start(10);
@@ -358,7 +362,7 @@ void ScriptEngine::waitTillDoneRunning() { · 78 unmodified lines
358 QThread::yieldCurrentThread();362 QThread::yieldCurrentThread();
359 }363 }
360 364
361 qCDebug(scriptengine) << "Script Engine has stopped:" << getFilename();365 scriptInfoMessage("Script Engine has stopped:" + getFilename());
362 }366 }
363}367}
364 368
@@ -397,10 +401,25 @@ void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scrip · 32 unmodified lines
397 emit scriptLoaded(url.toString());401 emit scriptLoaded(url.toString());
398}402}
399 403
404void ScriptEngine::scriptErrorMessage(const QString& message) {
405 qCCritical(scriptengine) << message;
406 emit errorMessage(message);
407}
408
409void ScriptEngine::scriptWarningMessage(const QString& message) {
410 qCWarning(scriptengine) << message;
411 emit warningMessage(message);
412}
413
414void ScriptEngine::scriptInfoMessage(const QString& message) {
415 qCInfo(scriptengine) << message;
416 emit infoMessage(message);
417}
418
400// FIXME - switch this to the new model of ScriptCache callbacks419// FIXME - switch this to the new model of ScriptCache callbacks
401void ScriptEngine::errorInLoadingScript(const QUrl& url) {420void ScriptEngine::errorInLoadingScript(const QUrl& url) {
402 qCDebug(scriptengine) << "ERROR Loading file:" << url.toString() << "line:" << __LINE__;421 scriptErrorMessage("ERROR Loading file:" + url.toString());
403 emit errorLoadingScript(_fileNameString); // ??422 emit errorLoadingScript(_fileNameString);
404}423}
405 424
406// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of425// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of
@@ -552,7 +571,7 @@ void ScriptEngine::init() { · 145 unmodified lines
552void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {571void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
553 if (QThread::currentThread() != thread()) {572 if (QThread::currentThread() != thread()) {
554#ifdef THREAD_DEBUGGING573#ifdef THREAD_DEBUGGING
555 qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";574 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
556#endif575#endif
557 QMetaObject::invokeMethod(this, "registerValue",576 QMetaObject::invokeMethod(this, "registerValue",
558 Q_ARG(const QString&, valueName),577 Q_ARG(const QString&, valueName),
@@ -582,7 +601,7 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { · 23 unmodified lines
582void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {601void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
583 if (QThread::currentThread() != thread()) {602 if (QThread::currentThread() != thread()) {
584#ifdef THREAD_DEBUGGING603#ifdef THREAD_DEBUGGING
585 qDebug() << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;604 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
586#endif605#endif
587 QMetaObject::invokeMethod(this, "registerGlobalObject",606 QMetaObject::invokeMethod(this, "registerGlobalObject",
588 Q_ARG(const QString&, name),607 Q_ARG(const QString&, name),
@@ -590,7 +609,7 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { · 1 unmodified line
590 return;609 return;
591 }610 }
592#ifdef THREAD_DEBUGGING611#ifdef THREAD_DEBUGGING
593 qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;612 qCDebug(scriptengine) << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
594#endif613#endif
595 614
596 if (!globalObject().property(name).isValid()) {615 if (!globalObject().property(name).isValid()) {
@@ -606,7 +625,7 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { · 9 unmodified lines
606void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {625void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
607 if (QThread::currentThread() != thread()) {626 if (QThread::currentThread() != thread()) {
608#ifdef THREAD_DEBUGGING627#ifdef THREAD_DEBUGGING
609 qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;628 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
610#endif629#endif
611 QMetaObject::invokeMethod(this, "registerFunction",630 QMetaObject::invokeMethod(this, "registerFunction",
612 Q_ARG(const QString&, name),631 Q_ARG(const QString&, name),
@@ -615,7 +634,7 @@ void ScriptEngine::registerFunction(const QString& name, QScriptEngine::Function · 2 unmodified lines
615 return;634 return;
616 }635 }
617#ifdef THREAD_DEBUGGING636#ifdef THREAD_DEBUGGING
618 qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;637 qCDebug(scriptengine) << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;
619#endif638#endif
620 639
621 QScriptValue scriptFun = newFunction(functionSignature, numArguments);640 QScriptValue scriptFun = newFunction(functionSignature, numArguments);
@@ -625,7 +644,7 @@ void ScriptEngine::registerFunction(const QString& name, QScriptEngine::Function · 3 unmodified lines
625void ScriptEngine::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {644void ScriptEngine::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
626 if (QThread::currentThread() != thread()) {645 if (QThread::currentThread() != thread()) {
627#ifdef THREAD_DEBUGGING646#ifdef THREAD_DEBUGGING
628 qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name;647 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name;
629#endif648#endif
630 QMetaObject::invokeMethod(this, "registerFunction",649 QMetaObject::invokeMethod(this, "registerFunction",
631 Q_ARG(const QString&, name),650 Q_ARG(const QString&, name),
@@ -634,7 +653,7 @@ void ScriptEngine::registerFunction(const QString& parent, const QString& name, · 2 unmodified lines
634 return;653 return;
635 }654 }
636#ifdef THREAD_DEBUGGING655#ifdef THREAD_DEBUGGING
637 qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;656 qCDebug(scriptengine) << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;
638#endif657#endif
639 658
640 QScriptValue object = globalObject().property(parent);659 QScriptValue object = globalObject().property(parent);
@@ -648,7 +667,7 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 7 unmodified lines
648 QScriptEngine::FunctionSignature setter, const QString& parent) {667 QScriptEngine::FunctionSignature setter, const QString& parent) {
649 if (QThread::currentThread() != thread()) {668 if (QThread::currentThread() != thread()) {
650#ifdef THREAD_DEBUGGING669#ifdef THREAD_DEBUGGING
651 qDebug() << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "670 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
652 " name:" << name << "parent:" << parent;671 " name:" << name << "parent:" << parent;
653#endif672#endif
654 QMetaObject::invokeMethod(this, "registerGetterSetter",673 QMetaObject::invokeMethod(this, "registerGetterSetter",
@@ -659,7 +678,7 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 4 unmodified lines
659 return;678 return;
660 }679 }
661#ifdef THREAD_DEBUGGING680#ifdef THREAD_DEBUGGING
662 qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;681 qCDebug(scriptengine) << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;
663#endif682#endif
664 683
665 QScriptValue setterFunction = newFunction(setter, 1);684 QScriptValue setterFunction = newFunction(setter, 1);
@@ -681,7 +700,7 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 15 unmodified lines
681void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {700void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
682 if (QThread::currentThread() != thread()) {701 if (QThread::currentThread() != thread()) {
683#ifdef THREAD_DEBUGGING702#ifdef THREAD_DEBUGGING
684 qDebug() << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "703 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
685 "entityID:" << entityID << " eventName:" << eventName;704 "entityID:" << entityID << " eventName:" << eventName;
686#endif705#endif
687 QMetaObject::invokeMethod(this, "removeEventHandler",706 QMetaObject::invokeMethod(this, "removeEventHandler",
@@ -691,7 +710,7 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin · 3 unmodified lines
691 return;710 return;
692 }711 }
693#ifdef THREAD_DEBUGGING712#ifdef THREAD_DEBUGGING
694 qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;713 qCDebug(scriptengine) << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
695#endif714#endif
696 715
697 if (!_registeredHandlers.contains(entityID)) {716 if (!_registeredHandlers.contains(entityID)) {
@@ -711,7 +730,7 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin · 13 unmodified lines
711void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {730void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
712 if (QThread::currentThread() != thread()) {731 if (QThread::currentThread() != thread()) {
713#ifdef THREAD_DEBUGGING732#ifdef THREAD_DEBUGGING
714 qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "733 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
715 "entityID:" << entityID << " eventName:" << eventName;734 "entityID:" << entityID << " eventName:" << eventName;
716#endif735#endif
717 736
@@ -722,7 +741,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 4 unmodified lines
722 return;741 return;
723 }742 }
724#ifdef THREAD_DEBUGGING743#ifdef THREAD_DEBUGGING
725 qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;744 qCDebug(scriptengine) << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
726#endif745#endif
727 746
728 if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script...747 if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script...
@@ -784,7 +803,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 55 unmodified lines
784 _registeredHandlers[entityID] = RegisteredEventHandlers();803 _registeredHandlers[entityID] = RegisteredEventHandlers();
785 }804 }
786 CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName];805 CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName];
787 CallbackData handlerData = {handler, currentEntityIdentifier, currentSandboxURL};806 CallbackData handlerData = { handler, currentEntityIdentifier, currentSandboxURL };
788 handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler().807 handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler().
789}808}
790 809
@@ -797,7 +816,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 6 unmodified lines
797 if (QThread::currentThread() != thread()) {816 if (QThread::currentThread() != thread()) {
798 QScriptValue result;817 QScriptValue result;
799#ifdef THREAD_DEBUGGING818#ifdef THREAD_DEBUGGING
800 qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "819 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
801 "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber;820 "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber;
802#endif821#endif
803 QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection,822 QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection,
@@ -810,7 +829,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 6 unmodified lines
810 829
811 // Check syntax830 // Check syntax
812 const QScriptProgram program(sourceCode, fileName, lineNumber);831 const QScriptProgram program(sourceCode, fileName, lineNumber);
813 if (!hasCorrectSyntax(program)) {832 if (!hasCorrectSyntax(program, this)) {
814 return QScriptValue();833 return QScriptValue();
815 }834 }
816 835
@@ -818,7 +837,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 1 unmodified line
818 const auto result = QScriptEngine::evaluate(program);837 const auto result = QScriptEngine::evaluate(program);
819 --_evaluatesPending;838 --_evaluatesPending;
820 839
821 const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName());840 const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName(), this);
822 emit evaluationFinished(result, hadUncaughtException);841 emit evaluationFinished(result, hadUncaughtException);
823 return result;842 return result;
824}843}
@@ -862,23 +881,48 @@ void ScriptEngine::run() { · 37 unmodified lines
862 // Throttle to SCRIPT_FPS881 // Throttle to SCRIPT_FPS
863 // We'd like to try to keep the script at a solid SCRIPT_FPS update rate. And so we will 882 // We'd like to try to keep the script at a solid SCRIPT_FPS update rate. And so we will
864 // calculate a sleepUntil to be the time from our start time until the original target883 // calculate a sleepUntil to be the time from our start time until the original target
865 // sleepUntil for this frame.884 // sleepUntil for this frame. This approach will allow us to "catch up" in the event
866 const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1);885 // that some of our script udpates/frames take a little bit longer than the target average
867 clock::time_point targetSleepUntil(startTime + thisFrame++ * FRAME_DURATION);886 // to execute.
868 887 // NOTE: if we go to variable SCRIPT_FPS, then we will need to reconsider this approach
869 // However, if our sleepUntil is not at least our average update time into the future888 const std::chrono::microseconds TARGET_SCRIPT_FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1);
870 // it means our script is taking too long in it's updates, and we want to punish the889 clock::time_point targetSleepUntil(startTime + (thisFrame++ * TARGET_SCRIPT_FRAME_DURATION));
871 // script a little bit. So we will force the sleepUntil to be at least our averageUpdate890
872 // time into the future.891 // However, if our sleepUntil is not at least our average update and timer execution time
892 // into the future it means our script is taking too long in its updates, and we want to
893 // punish the script a little bit. So we will force the sleepUntil to be at least our
894 // averageUpdate + averageTimerPerFrame time into the future.
873 auto averageUpdate = totalUpdates / thisFrame;895 auto averageUpdate = totalUpdates / thisFrame;
874 auto sleepUntil = std::max(targetSleepUntil, beforeSleep + averageUpdate);896 auto averageTimerPerFrame = _totalTimerExecution / thisFrame;
897 auto averageTimerAndUpdate = averageUpdate + averageTimerPerFrame;
898 auto sleepUntil = std::max(targetSleepUntil, beforeSleep + averageTimerAndUpdate);
875 899
876 // We don't want to actually sleep for too long, because it causes our scripts to hang 900 // We don't want to actually sleep for too long, because it causes our scripts to hang
877 // on shutdown and stop... so we want to loop and sleep until we've spent our time in 901 // on shutdown and stop... so we want to loop and sleep until we've spent our time in
878 // purgatory, constantly checking to see if our script was asked to end902 // purgatory, constantly checking to see if our script was asked to end
903 bool processedEvents = false;
879 while (!_isFinished && clock::now() < sleepUntil) {904 while (!_isFinished && clock::now() < sleepUntil) {
905
880 QCoreApplication::processEvents(); // before we sleep again, give events a chance to process906 QCoreApplication::processEvents(); // before we sleep again, give events a chance to process
881 auto thisSleepUntil = std::min(sleepUntil, clock::now() + FRAME_DURATION);907 processedEvents = true;
908
909 // If after processing events, we're past due, exit asap
910 if (clock::now() >= sleepUntil) {
911 break;
912 }
913
914 // determine how long before the next timer should fire, we'd ideally like to sleep just
915 // that long, so the next processEvents() will allow the timers to fire on time.
916 const std::chrono::microseconds minTimerTimeRemaining(USECS_PER_MSEC * getTimersRemainingTime());
917
918 // However, if we haven't yet slept at least as long as our average timer per frame, then we will
919 // punish the timers to at least wait as long as the average run time of the timers.
920 auto untilTimer = std::max(minTimerTimeRemaining, averageTimerPerFrame);
921
922 // choose the closest time point, our
923 auto remainingSleepUntil = std::chrono::duration_cast<std::chrono::microseconds>(sleepUntil - clock::now());
924 auto closestUntil = std::min(remainingSleepUntil, untilTimer);
925 auto thisSleepUntil = std::min(sleepUntil, clock::now() + closestUntil);
882 std::this_thread::sleep_until(thisSleepUntil);926 std::this_thread::sleep_until(thisSleepUntil);
883 }927 }
884 928
@@ -903,7 +947,10 @@ void ScriptEngine::run() { · 18 unmodified lines
903 break;947 break;
904 }948 }
905 949
906 QCoreApplication::processEvents();950 // Only call this if we didn't processEvents as part of waiting for next frame
951 if (!processedEvents) {
952 QCoreApplication::processEvents();
953 }
907 954
908 if (_isFinished) {955 if (_isFinished) {
909 break;956 break;
@@ -935,10 +982,10 @@ void ScriptEngine::run() { · 25 unmodified lines
935 _lastUpdate = now;982 _lastUpdate = now;
936 983
937 // Debug and clear exceptions984 // Debug and clear exceptions
938 hadUncaughtExceptions(*this, _fileNameString);985 hadUncaughtExceptions(*this, _fileNameString, this);
939 }986 }
940 987
941 qCDebug(scriptengine) << "Script Engine stopping:" << getFilename();988 scriptInfoMessage("Script Engine stopping:" + getFilename());
942 989
943 stopAllTimers(); // make sure all our timers are stopped if the script is ending990 stopAllTimers(); // make sure all our timers are stopped if the script is ending
944 emit scriptEnding();991 emit scriptEnding();
@@ -966,6 +1013,21 @@ void ScriptEngine::run() { · 21 unmodified lines
966 emit doneRunning();1013 emit doneRunning();
967}1014}
968 1015
1016quint64 ScriptEngine::getTimersRemainingTime() {
1017 quint64 minimumTime = USECS_PER_SECOND; // anything larger than this can be ignored
1018 QMutableHashIterator<QTimer*, CallbackData> i(_timerFunctionMap);
1019 while (i.hasNext()) {
1020 i.next();
1021 QTimer* timer = i.key();
1022 int remainingTime = timer->remainingTime();
1023 if (remainingTime >= 0) {
1024 minimumTime = std::min((quint64)remainingTime, minimumTime);
1025 }
1026 }
1027 return minimumTime;
1028}
1029
1030
969// NOTE: This is private because it must be called on the same thread that created the timers, which is why1031// NOTE: This is private because it must be called on the same thread that created the timers, which is why
970// we want to only call it in our own run "shutdown" processing.1032// we want to only call it in our own run "shutdown" processing.
971void ScriptEngine::stopAllTimers() {1033void ScriptEngine::stopAllTimers() {
@@ -1011,7 +1073,7 @@ void ScriptEngine::stop(bool marshal) { · 39 unmodified lines
1011void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) {1073void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) {
1012 if (QThread::currentThread() != thread()) {1074 if (QThread::currentThread() != thread()) {
1013#ifdef THREAD_DEBUGGING1075#ifdef THREAD_DEBUGGING
1014 qDebug() << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;1076 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
1015#endif1077#endif
1016 QMetaObject::invokeMethod(this, "callAnimationStateHandler",1078 QMetaObject::invokeMethod(this, "callAnimationStateHandler",
1017 Q_ARG(QScriptValue, callback),1079 Q_ARG(QScriptValue, callback),
@@ -1045,7 +1107,7 @@ void ScriptEngine::timerFired() { · 27 unmodified lines
1045 {1107 {
1046 auto engine = DependencyManager::get<ScriptEngines>();1108 auto engine = DependencyManager::get<ScriptEngines>();
1047 if (!engine || engine->isStopped()) {1109 if (!engine || engine->isStopped()) {
1048 qCDebug(scriptengine) << "Script.timerFired() while shutting down is ignored... parent script:" << getFilename();1110 scriptWarningMessage("Script.timerFired() while shutting down is ignored... parent script:" + getFilename());
1049 return; // bail early1111 return; // bail early
1050 }1112 }
1051 }1113 }
@@ -1061,7 +1123,12 @@ void ScriptEngine::timerFired() { · 9 unmodified lines
1061 1123
1062 // call the associated JS function, if it exists1124 // call the associated JS function, if it exists
1063 if (timerData.function.isValid()) {1125 if (timerData.function.isValid()) {
1126 auto preTimer = p_high_resolution_clock::now();
1064 callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList());1127 callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList());
1128 auto postTimer = p_high_resolution_clock::now();
1129 auto elapsed = (postTimer - preTimer);
1130 _totalTimerExecution += std::chrono::duration_cast<std::chrono::microseconds>(elapsed);
1131
1065 }1132 }
1066}1133}
1067 1134
@@ -1071,12 +1138,18 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 3 unmodified lines
1071 QTimer* newTimer = new QTimer(this);1138 QTimer* newTimer = new QTimer(this);
1072 newTimer->setSingleShot(isSingleShot);1139 newTimer->setSingleShot(isSingleShot);
1073 1140
1141 // The default timer type is not very accurate below about 200ms http://doc.qt.io/qt-5/qt.html#TimerType-enum
1142 static const int MIN_TIMEOUT_FOR_COARSE_TIMER = 200;
1143 if (intervalMS < MIN_TIMEOUT_FOR_COARSE_TIMER) {
1144 newTimer->setTimerType(Qt::PreciseTimer);
1145 }
1146
1074 connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);1147 connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
1075 1148
1076 // make sure the timer stops when the script does1149 // make sure the timer stops when the script does
1077 connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);1150 connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
1078 1151
1079 CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL};1152 CallbackData timerData = {function, currentEntityIdentifier, currentSandboxURL };
1080 _timerFunctionMap.insert(newTimer, timerData);1153 _timerFunctionMap.insert(newTimer, timerData);
1081 1154
1082 newTimer->start(intervalMS);1155 newTimer->start(intervalMS);
@@ -1085,7 +1158,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 2 unmodified lines
1085 1158
1086QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) {1159QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) {
1087 if (DependencyManager::get<ScriptEngines>()->isStopped()) {1160 if (DependencyManager::get<ScriptEngines>()->isStopped()) {
1088 qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename();1161 scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename());
1089 return NULL; // bail early1162 return NULL; // bail early
1090 }1163 }
1091 1164
@@ -1094,7 +1167,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) · 2 unmodified lines
1094 1167
1095QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) {1168QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) {
1096 if (DependencyManager::get<ScriptEngines>()->isStopped()) {1169 if (DependencyManager::get<ScriptEngines>()->isStopped()) {
1097 qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename();1170 scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename());
1098 return NULL; // bail early1171 return NULL; // bail early
1099 }1172 }
1100 1173
@@ -1154,8 +1227,8 @@ void ScriptEngine::print(const QString& message) { · 53 unmodified lines
1154// all of the files have finished loading.1227// all of the files have finished loading.
1155void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {1228void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {
1156 if (DependencyManager::get<ScriptEngines>()->isStopped()) {1229 if (DependencyManager::get<ScriptEngines>()->isStopped()) {
1157 qCDebug(scriptengine) << "Script.include() while shutting down is ignored..."1230 scriptWarningMessage("Script.include() while shutting down is ignored... includeFiles:"
1158 << "includeFiles:" << includeFiles << "parent script:" << getFilename();1231 + includeFiles.join(",") + "parent script:" + getFilename());
1159 return; // bail early1232 return; // bail early
1160 }1233 }
1161 QList<QUrl> urls;1234 QList<QUrl> urls;
@@ -1183,7 +1256,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 21 unmodified lines
1183 thisURL = expandScriptUrl(QUrl::fromLocalFile(expandScriptPath(file)));1256 thisURL = expandScriptUrl(QUrl::fromLocalFile(expandScriptPath(file)));
1184 QUrl defaultScriptsLoc = defaultScriptsLocation();1257 QUrl defaultScriptsLoc = defaultScriptsLocation();
1185 if (!defaultScriptsLoc.isParentOf(thisURL)) {1258 if (!defaultScriptsLoc.isParentOf(thisURL)) {
1186 qDebug() << "ScriptEngine::include -- skipping" << file << "-- outside of standard libraries";1259 scriptWarningMessage("Script.include() -- skipping" + file + "-- outside of standard libraries");
1187 continue;1260 continue;
1188 }1261 }
1189 isStandardLibrary = true;1262 isStandardLibrary = true;
@@ -1194,8 +1267,9 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 4 unmodified lines
1194 if (!isStandardLibrary && !currentSandboxURL.isEmpty() && (thisURL.scheme() == "file") &&1267 if (!isStandardLibrary && !currentSandboxURL.isEmpty() && (thisURL.scheme() == "file") &&
1195 (currentSandboxURL.scheme() != "file" ||1268 (currentSandboxURL.scheme() != "file" ||
1196 !thisURL.toString(strippingFlags).startsWith(currentSandboxURL.toString(strippingFlags), getSensitivity()))) {1269 !thisURL.toString(strippingFlags).startsWith(currentSandboxURL.toString(strippingFlags), getSensitivity()))) {
1197 qCWarning(scriptengine) << "Script.include() ignoring file path"1270
1198 << thisURL << "outside of original entity script" << currentSandboxURL;1271 scriptWarningMessage("Script.include() ignoring file path" + thisURL.toString()
1272 + "outside of original entity script" + currentSandboxURL.toString());
1199 } else {1273 } else {
1200 // We could also check here for CORS, but we don't yet.1274 // We could also check here for CORS, but we don't yet.
1201 // It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here.1275 // It turns out that QUrl.resolve will not change hosts and copy authority, so we don't need to check that here.
@@ -1217,7 +1291,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 15 unmodified lines
1217 for (QUrl url : urls) {1291 for (QUrl url : urls) {
1218 QString contents = data[url];1292 QString contents = data[url];
1219 if (contents.isNull()) {1293 if (contents.isNull()) {
1220 qCDebug(scriptengine) << "Error loading file: " << url << "line:" << __LINE__;1294 scriptErrorMessage("Error loading file: " + url.toString());
1221 } else {1295 } else {
1222 std::lock_guard<std::recursive_mutex> lock(_lock);1296 std::lock_guard<std::recursive_mutex> lock(_lock);
1223 if (!_includedURLs.contains(url)) {1297 if (!_includedURLs.contains(url)) {
@@ -1231,7 +1305,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 7 unmodified lines
1231 1305
1232 doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation);1306 doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation);
1233 } else {1307 } else {
1234 qCDebug(scriptengine) << "Script.include() skipping evaluation of previously included url:" << url;1308 scriptWarningMessage("Script.include() skipping evaluation of previously included url:" + url.toString());
1235 }1309 }
1236 }1310 }
1237 }1311 }
@@ -1260,8 +1334,8 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 22 unmodified lines
1260 1334
1261void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {1335void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
1262 if (DependencyManager::get<ScriptEngines>()->isStopped()) {1336 if (DependencyManager::get<ScriptEngines>()->isStopped()) {
1263 qCDebug(scriptengine) << "Script.include() while shutting down is ignored... "1337 scriptWarningMessage("Script.include() while shutting down is ignored... includeFile:"
1264 << "includeFile:" << includeFile << "parent script:" << getFilename();1338 + includeFile + "parent script:" + getFilename());
1265 return; // bail early1339 return; // bail early
1266 }1340 }
1267 1341
@@ -1275,13 +1349,13 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { · 7 unmodified lines
1275// the Application or other context will connect to in order to know to actually load the script1349// the Application or other context will connect to in order to know to actually load the script
1276void ScriptEngine::load(const QString& loadFile) {1350void ScriptEngine::load(const QString& loadFile) {
1277 if (DependencyManager::get<ScriptEngines>()->isStopped()) {1351 if (DependencyManager::get<ScriptEngines>()->isStopped()) {
1278 qCDebug(scriptengine) << "Script.load() while shutting down is ignored... "1352 scriptWarningMessage("Script.load() while shutting down is ignored... loadFile:"
1279 << "loadFile:" << loadFile << "parent script:" << getFilename();1353 + loadFile + "parent script:" + getFilename());
1280 return; // bail early1354 return; // bail early
1281 }1355 }
1282 if (!currentEntityIdentifier.isInvalidID()) {1356 if (!currentEntityIdentifier.isInvalidID()) {
1283 qCWarning(scriptengine) << "Script.load() from entity script is ignored... "1357 scriptWarningMessage("Script.load() from entity script is ignored... loadFile:"
1284 << "loadFile:" << loadFile << "parent script:" << getFilename();1358 + loadFile + "parent script:" + getFilename());
1285 return; // bail early1359 return; // bail early
1286 }1360 }
1287 1361
@@ -1298,7 +1372,7 @@ void ScriptEngine::load(const QString& loadFile) { · 10 unmodified lines
1298// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args1372// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
1299void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHandlerArgs) {1373void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHandlerArgs) {
1300 if (QThread::currentThread() != thread()) {1374 if (QThread::currentThread() != thread()) {
1301 qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";1375 qCDebug(scriptengine) << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
1302 assert(false);1376 assert(false);
1303 return ;1377 return ;
1304 }1378 }
@@ -1332,7 +1406,7 @@ void ScriptEngine::loadEntityScript(QWeakPointer<ScriptEngine> theEngine, const · 27 unmodified lines
1332 QSharedPointer<ScriptEngine> strongEngine = theEngine.toStrongRef();1406 QSharedPointer<ScriptEngine> strongEngine = theEngine.toStrongRef();
1333 if (strongEngine) {1407 if (strongEngine) {
1334#ifdef THREAD_DEBUGGING1408#ifdef THREAD_DEBUGGING
1335 qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread ["1409 qCDebug(scriptengine) << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread ["
1336 << QThread::currentThread() << "] expected thread [" << strongEngine->thread() << "]";1410 << QThread::currentThread() << "] expected thread [" << strongEngine->thread() << "]";
1337#endif1411#endif
1338 strongEngine->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);1412 strongEngine->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);
@@ -1345,7 +1419,7 @@ void ScriptEngine::loadEntityScript(QWeakPointer<ScriptEngine> theEngine, const · 6 unmodified lines
1345void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {1419void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {
1346 if (QThread::currentThread() != thread()) {1420 if (QThread::currentThread() != thread()) {
1347#ifdef THREAD_DEBUGGING1421#ifdef THREAD_DEBUGGING
1348 qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread ["1422 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread ["
1349 << QThread::currentThread() << "], invoking on correct thread [" << thread()1423 << QThread::currentThread() << "], invoking on correct thread [" << thread()
1350 << "] " "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:"1424 << "] " "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:"
1351 << contents << "isURL:" << isURL << "success:" << success;1425 << contents << "isURL:" << isURL << "success:" << success;
@@ -1361,7 +1435,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 9 unmodified lines
1361 }1435 }
1362 1436
1363#ifdef THREAD_DEBUGGING1437#ifdef THREAD_DEBUGGING
1364 qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";1438 qCDebug(scriptengine) << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
1365#endif1439#endif
1366 1440
1367 auto scriptCache = DependencyManager::get<ScriptCache>();1441 auto scriptCache = DependencyManager::get<ScriptCache>();
@@ -1369,7 +1443,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 1 unmodified line
1369 auto fileName = isURL ? scriptOrURL : "EmbeddedEntityScript";1443 auto fileName = isURL ? scriptOrURL : "EmbeddedEntityScript";
1370 1444
1371 QScriptProgram program(contents, fileName);1445 QScriptProgram program(contents, fileName);
1372 if (!hasCorrectSyntax(program)) {1446 if (!hasCorrectSyntax(program, this)) {
1373 if (!isFileUrl) {1447 if (!isFileUrl) {
1374 scriptCache->addScriptToBadScriptList(scriptOrURL);1448 scriptCache->addScriptToBadScriptList(scriptOrURL);
1375 }1449 }
@@ -1397,7 +1471,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 21 unmodified lines
1397 });1471 });
1398 testConstructor = sandbox.evaluate(program);1472 testConstructor = sandbox.evaluate(program);
1399 }1473 }
1400 if (hadUncaughtExceptions(sandbox, program.fileName())) {1474 if (hadUncaughtExceptions(sandbox, program.fileName(), this)) {
1401 return;1475 return;
1402 }1476 }
1403 1477
@@ -1411,10 +1485,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 7 unmodified lines
1411 if (testConstructorValue.size() > maxTestConstructorValueSize) {1485 if (testConstructorValue.size() > maxTestConstructorValueSize) {
1412 testConstructorValue = testConstructorValue.mid(0, maxTestConstructorValueSize) + "...";1486 testConstructorValue = testConstructorValue.mid(0, maxTestConstructorValueSize) + "...";
1413 }1487 }
1414 qCDebug(scriptengine) << "Error -- ScriptEngine::loadEntityScript() entity:" << entityID1488 scriptErrorMessage("Error -- ScriptEngine::loadEntityScript() entity:" + entityID.toString()
1415 << "failed to load entity script -- expected a function, got " + testConstructorType1489 + "failed to load entity script -- expected a function, got " + testConstructorType
1416 << "," << testConstructorValue1490 + "," + testConstructorValue
1417 << "," << scriptOrURL;1491 + "," + scriptOrURL);
1418 1492
1419 if (!isFileUrl) {1493 if (!isFileUrl) {
1420 scriptCache->addScriptToBadScriptList(scriptOrURL);1494 scriptCache->addScriptToBadScriptList(scriptOrURL);
@@ -1449,7 +1523,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 28 unmodified lines
1449void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {1523void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
1450 if (QThread::currentThread() != thread()) {1524 if (QThread::currentThread() != thread()) {
1451#ifdef THREAD_DEBUGGING1525#ifdef THREAD_DEBUGGING
1452 qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "1526 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
1453 "entityID:" << entityID;1527 "entityID:" << entityID;
1454#endif1528#endif
1455 1529
@@ -1458,7 +1532,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 2 unmodified lines
1458 return;1532 return;
1459 }1533 }
1460#ifdef THREAD_DEBUGGING1534#ifdef THREAD_DEBUGGING
1461 qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] "1535 qCDebug(scriptengine) << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] "
1462 "entityID:" << entityID;1536 "entityID:" << entityID;
1463#endif1537#endif
1464 1538
@@ -1472,14 +1546,14 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 7 unmodified lines
1472void ScriptEngine::unloadAllEntityScripts() {1546void ScriptEngine::unloadAllEntityScripts() {
1473 if (QThread::currentThread() != thread()) {1547 if (QThread::currentThread() != thread()) {
1474#ifdef THREAD_DEBUGGING1548#ifdef THREAD_DEBUGGING
1475 qDebug() << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";1549 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
1476#endif1550#endif
1477 1551
1478 QMetaObject::invokeMethod(this, "unloadAllEntityScripts");1552 QMetaObject::invokeMethod(this, "unloadAllEntityScripts");
1479 return;1553 return;
1480 }1554 }
1481#ifdef THREAD_DEBUGGING1555#ifdef THREAD_DEBUGGING
1482 qDebug() << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]";1556 qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]";
1483#endif1557#endif
1484 foreach(const EntityItemID& entityID, _entityScripts.keys()) {1558 foreach(const EntityItemID& entityID, _entityScripts.keys()) {
1485 callEntityScriptMethod(entityID, "unload");1559 callEntityScriptMethod(entityID, "unload");
@@ -1487,13 +1561,13 @@ void ScriptEngine::unloadAllEntityScripts() { · 1 unmodified line
1487 _entityScripts.clear();1561 _entityScripts.clear();
1488 1562
1489#ifdef DEBUG_ENGINE_STATE1563#ifdef DEBUG_ENGINE_STATE
1490 qDebug() << "---- CURRENT STATE OF ENGINE: --------------------------";1564 qCDebug(scriptengine) << "---- CURRENT STATE OF ENGINE: --------------------------";
1491 QScriptValueIterator it(globalObject());1565 QScriptValueIterator it(globalObject());
1492 while (it.hasNext()) {1566 while (it.hasNext()) {
1493 it.next();1567 it.next();
1494 qDebug() << it.name() << ":" << it.value().toString();1568 qCDebug(scriptengine) << it.name() << ":" << it.value().toString();
1495 }1569 }
1496 qDebug() << "--------------------------------------------------------";1570 qCDebug(scriptengine) << "--------------------------------------------------------";
1497#endif // DEBUG_ENGINE_STATE1571#endif // DEBUG_ENGINE_STATE
1498}1572}
1499 1573
@@ -1514,7 +1588,7 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 14 unmodified lines
1514 QString filePath = QUrl(details.scriptText).toLocalFile();1588 QString filePath = QUrl(details.scriptText).toLocalFile();
1515 auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();1589 auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();
1516 if (lastModified > details.lastModified) {1590 if (lastModified > details.lastModified) {
1517 qCDebug(scriptengine) << "Reloading modified script " << details.scriptText;1591 scriptInfoMessage("Reloading modified script " + details.scriptText);
1518 1592
1519 QFile file(filePath);1593 QFile file(filePath);
1520 file.open(QIODevice::ReadOnly);1594 file.open(QIODevice::ReadOnly);
@@ -1522,7 +1596,7 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 1 unmodified line
1522 this->unloadEntityScript(entityID);1596 this->unloadEntityScript(entityID);
1523 this->entityScriptContentAvailable(entityID, details.scriptText, scriptContents, true, true);1597 this->entityScriptContentAvailable(entityID, details.scriptText, scriptContents, true, true);
1524 if (!_entityScripts.contains(entityID)) {1598 if (!_entityScripts.contains(entityID)) {
1525 qWarning() << "Reload script " << details.scriptText << " failed";1599 scriptWarningMessage("Reload script " + details.scriptText + " failed");
1526 } else {1600 } else {
1527 details = _entityScripts[entityID];1601 details = _entityScripts[entityID];
1528 }1602 }
@@ -1549,7 +1623,7 @@ void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, const QUrl& s · 20 unmodified lines
1549#else1623#else
1550 operation();1624 operation();
1551#endif1625#endif
1552 hadUncaughtExceptions(*this, _fileNameString);1626 hadUncaughtExceptions(*this, _fileNameString, this);
1553 1627
1554 currentEntityIdentifier = oldIdentifier;1628 currentEntityIdentifier = oldIdentifier;
1555 currentSandboxURL = oldSandboxURL;1629 currentSandboxURL = oldSandboxURL;
@@ -1564,7 +1638,7 @@ void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& · 8 unmodified lines
1564void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) {1638void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) {
1565 if (QThread::currentThread() != thread()) {1639 if (QThread::currentThread() != thread()) {
1566#ifdef THREAD_DEBUGGING1640#ifdef THREAD_DEBUGGING
1567 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "1641 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
1568 "entityID:" << entityID << "methodName:" << methodName;1642 "entityID:" << entityID << "methodName:" << methodName;
1569#endif1643#endif
1570 1644
@@ -1575,7 +1649,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines
1575 return;1649 return;
1576 }1650 }
1577#ifdef THREAD_DEBUGGING1651#ifdef THREAD_DEBUGGING
1578 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "1652 qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
1579 "entityID:" << entityID << "methodName:" << methodName;1653 "entityID:" << entityID << "methodName:" << methodName;
1580#endif1654#endif
1581 1655
@@ -1596,7 +1670,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 14 unmodified lines
1596void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event) {1670void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event) {
1597 if (QThread::currentThread() != thread()) {1671 if (QThread::currentThread() != thread()) {
1598#ifdef THREAD_DEBUGGING1672#ifdef THREAD_DEBUGGING
1599 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "1673 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
1600 "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";1674 "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
1601#endif1675#endif
1602 1676
@@ -1607,7 +1681,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines
1607 return;1681 return;
1608 }1682 }
1609#ifdef THREAD_DEBUGGING1683#ifdef THREAD_DEBUGGING
1610 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "1684 qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
1611 "entityID:" << entityID << "methodName:" << methodName << "event: pointerEvent";1685 "entityID:" << entityID << "methodName:" << methodName << "event: pointerEvent";
1612#endif1686#endif
1613 1687
@@ -1628,7 +1702,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 14 unmodified lines
1628void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) {1702void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) {
1629 if (QThread::currentThread() != thread()) {1703 if (QThread::currentThread() != thread()) {
1630#ifdef THREAD_DEBUGGING1704#ifdef THREAD_DEBUGGING
1631 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "1705 qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
1632 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";1706 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
1633#endif1707#endif
1634 1708
@@ -1640,7 +1714,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 5 unmodified lines
1640 return;1714 return;
1641 }1715 }
1642#ifdef THREAD_DEBUGGING1716#ifdef THREAD_DEBUGGING
1643 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "1717 qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
1644 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";1718 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
1645#endif1719#endif
1646 1720