History

resolve conflicts on merge with upstream/master

Stephen Birarda committed 10 years ago

Commit 4573e5c2 parents a7dfc99 85b8266325 files · +10929 −5218Browse files

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

Unified · Split

libraries/script-engine/src/ScriptEngine.cpp+159−144
@@ -24,6 +24,7 @@ · 23 unmodified lines
2424 #include <AudioEffectOptions.h>
2525 #include <AvatarData.h>
2626 #include <EntityScriptingInterface.h>
27+#include <MessagesClient.h>
2728 #include <NetworkAccessManager.h>
2829 #include <NodeList.h>
2930 #include <udt/PacketHeaders.h>
@@ -46,6 +47,7 @@ · 16 unmodified lines
4647 #include "WebSocketClass.h"
4748
4849 #include "SceneScriptingInterface.h"
50+#include "RecordingScriptingInterface.h"
4951
5052 #include "MIDIEvent.h"
5153
@@ -60,14 +62,14 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ · 8 unmodified lines
6062 }
6163 message += context->argument(i).toString();
6264 }
63− qCDebug(scriptengine) << "script:print()<<" << message;
64−
65+ qCDebug(scriptengine).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline
66+
6567 message = message.replace("\\", "\\\\")
6668 .replace("\n", "\\n")
6769 .replace("\r", "\\r")
6870 .replace("'", "\\'");
6971 engine->evaluate("Script.print('" + message + "')");
70−
72+
7173 return QScriptValue();
7274 }
7375
@@ -108,7 +110,7 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName · 34 unmodified lines
108110 const auto exception = engine.uncaughtException().toString();
109111 const auto line = QString::number(engine.uncaughtExceptionLineNumber());
110112 engine.clearExceptions();
111−
113+
112114 auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
113115 if (!backtrace.empty()) {
114116 static const auto lineSeparator = "\n ";
@@ -121,16 +123,11 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName · 6 unmodified lines
121123 }
122124
123125 ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) :
124− _scriptContents(scriptContents),
125− _isFinished(false),
126− _isRunning(false),
127− _isInitialized(false),
128− _timerFunctionMap(),
129− _wantSignals(wantSignals),
130− _fileNameString(fileNameString),
131− _isUserLoaded(false),
132− _isReloading(false),
133− _arrayBufferClass(new ArrayBufferClass(this))
126+_scriptContents(scriptContents),
127+_timerFunctionMap(),
128+_wantSignals(wantSignals),
129+_fileNameString(fileNameString),
130+_arrayBufferClass(new ArrayBufferClass(this))
134131 {
135132 _allScriptsMutex.lock();
136133 _allKnownScriptEngines.insert(this);
@@ -138,6 +135,8 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 1 unmodified line
138135 }
139136
140137 ScriptEngine::~ScriptEngine() {
138+ qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename();
139+
141140 // If we're not already in the middle of stopping all scripts, then we should remove ourselves
142141 // from the list of running scripts. We don't do this if we're in the process of stopping all scripts
143142 // because that method removes scripts from its list as it iterates them
@@ -148,25 +147,35 @@ ScriptEngine::~ScriptEngine() { · 4 unmodified lines
148147 }
149148 }
150149
150+void ScriptEngine::disconnectNonEssentialSignals() {
151+ disconnect();
152+ connect(this, &ScriptEngine::doneRunning, thread(), &QThread::quit);
153+}
154+
151155 void ScriptEngine::runInThread() {
156+ _isThreaded = true;
152157 QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete
153158 QString scriptEngineName = QString("Script Thread:") + getFilename();
154159 workerThread->setObjectName(scriptEngineName);
155−
160+
161+ // NOTE: If you connect any essential signals for proper shutdown or cleanup of
162+ // the script engine, make sure to add code to "reconnect" them to the
163+ // disconnectNonEssentialSignals() method
164+
156165 // when the worker thread is started, call our engine's run..
157166 connect(workerThread, &QThread::started, this, &ScriptEngine::run);
158−
167+
159168 // tell the thread to stop when the script engine is done
160169 connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
161−
170+
162171 // when the thread is finished, add thread to the deleteLater queue
163172 connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
164−
173+
165174 // when the thread is finished, add scriptEngine to the deleteLater queue
166175 connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater);
167−
176+
168177 moveToThread(workerThread);
169−
178+
170179 // Starts an event loop, and emits workerThread->started()
171180 workerThread->start();
172181 }
@@ -174,28 +183,29 @@ void ScriptEngine::runInThread() { · 1 unmodified line
174183 QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines;
175184 QMutex ScriptEngine::_allScriptsMutex;
176185 bool ScriptEngine::_stoppingAllScripts = false;
177−bool ScriptEngine::_doneRunningThisScript = false;
178186
179187 void ScriptEngine::stopAllScripts(QObject* application) {
180188 _allScriptsMutex.lock();
181189 _stoppingAllScripts = true;
182−
190+
191+ qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size();
192+
183193 QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
184194 while (i.hasNext()) {
185195 ScriptEngine* scriptEngine = i.next();
186−
196+
187197 QString scriptName = scriptEngine->getFilename();
188−
198+
189199 // NOTE: typically all script engines are running. But there's at least one known exception to this, the
190200 // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using
191201 // them. We don't need to stop scripts that aren't running.
192202 if (scriptEngine->isRunning()) {
193−
203+
194204 // If the script is running, but still evaluating then we need to wait for its evaluation step to
195205 // complete. After that we can handle the stop process appropriately
196206 if (scriptEngine->evaluatePending()) {
197207 while (scriptEngine->evaluatePending()) {
198−
208+
199209 // This event loop allows any started, but not yet finished evaluate() calls to complete
200210 // we need to let these complete so that we can be guaranteed that the script engine isn't
201211 // in a partially setup state, which can confuse our shutdown unwinding.
@@ -204,42 +214,42 @@ void ScriptEngine::stopAllScripts(QObject* application) { · 2 unmodified lines
204214 loop.exec();
205215 }
206216 }
207−
217+
208218 // We disconnect any script engine signals from the application because we don't want to do any
209219 // extra stopScript/loadScript processing that the Application normally does when scripts start
210220 // and stop. We can safely short circuit this because we know we're in the "quitting" process
211221 scriptEngine->disconnect(application);
212−
222+
213223 // Calling stop on the script engine will set it's internal _isFinished state to true, and result
214224 // in the ScriptEngine gracefully ending it's run() method.
215225 scriptEngine->stop();
216−
226+
217227 // We need to wait for the engine to be done running before we proceed, because we don't
218228 // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing
219229 // any application state after we leave this stopAllScripts() method
230+ qCDebug(scriptengine) << "waiting on script:" << scriptName;
220231 scriptEngine->waitTillDoneRunning();
221−
232+ qCDebug(scriptengine) << "done waiting on script:" << scriptName;
233+
222234 // If the script is stopped, we can remove it from our set
223235 i.remove();
224236 }
225237 }
226238 _stoppingAllScripts = false;
227239 _allScriptsMutex.unlock();
240+ qCDebug(scriptengine) << "DONE Stopping all scripts....";
228241 }
229242
230243
231244 void ScriptEngine::waitTillDoneRunning() {
232245 // If the script never started running or finished running before we got here, we don't need to wait for it
233− if (_isRunning) {
234−
235− _doneRunningThisScript = false; // NOTE: this is static, we serialize our waiting for scripts to finish
236−
246+ if (_isRunning && _isThreaded) {
247+
237248 // NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts()
238249 // we want the application thread to continue to process events, because the scripts will likely need to
239250 // marshall messages across to the main thread. For example if they access Settings or Meny in any of their
240251 // shutdown code.
241− while (!_doneRunningThisScript) {
242−
252+ while (thread()->isRunning()) {
243253 // process events for the main application thread, allowing invokeMethod calls to pass between threads
244254 QCoreApplication::processEvents();
245255 }
@@ -261,12 +271,12 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { · 15 unmodified lines
261271 if (_isRunning) {
262272 return;
263273 }
264−
274+
265275 _fileNameString = scriptURL.toString();
266276 _isReloading = reload;
267−
277+
268278 QUrl url(scriptURL);
269−
279+
270280 bool isPending;
271281 auto scriptCache = DependencyManager::get<ScriptCache>();
272282 scriptCache->getScript(url, this, isPending, reload);
@@ -313,12 +323,12 @@ void ScriptEngine::init() { · 40 unmodified lines
313323 if (_isInitialized) {
314324 return; // only initialize once
315325 }
316−
326+
317327 _isInitialized = true;
318−
328+
319329 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
320330 entityScriptingInterface->init();
321−
331+
322332 // register various meta-types
323333 registerMetaTypes(this);
324334 registerMIDIMetaTypes(this);
@@ -327,30 +337,30 @@ void ScriptEngine::init() { · 2 unmodified lines
327337 registerAnimationTypes(this);
328338 registerAvatarTypes(this);
329339 registerAudioMetaTypes(this);
330−
340+
331341 qScriptRegisterMetaType(this, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue);
332342 qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
333343 qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
334344 qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
335345 qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
336346 qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this);
337−
347+
338348 qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this);
339349 qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this);
340350 qScriptRegisterSequenceMetaType<QVector<QString> >(this);
341−
351+
342352 QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor);
343353 globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue);
344−
354+
345355 QScriptValue webSocketConstructorValue = newFunction(WebSocketClass::constructor);
346356 globalObject().setProperty("WebSocket", webSocketConstructorValue);
347−
357+
348358 QScriptValue printConstructorValue = newFunction(debugPrint);
349359 globalObject().setProperty("print", printConstructorValue);
350−
360+
351361 QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor);
352362 globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue);
353−
363+
354364 qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue);
355365 qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);
356366 qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue);
@@ -358,7 +368,7 @@ void ScriptEngine::init() { · 1 unmodified line
358368 qScriptRegisterMetaType(this, webSocketToScriptValue, webSocketFromScriptValue);
359369 qScriptRegisterMetaType(this, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue);
360370 qScriptRegisterMetaType(this, wscReadyStateToScriptValue, wscReadyStateFromScriptValue);
361−
371+
362372 registerGlobalObject("Script", this);
363373 registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());
364374 registerGlobalObject("Entities", entityScriptingInterface.data());
@@ -366,15 +376,22 @@ void ScriptEngine::init() { · 1 unmodified line
366376 registerGlobalObject("Vec3", &_vec3Library);
367377 registerGlobalObject("Uuid", &_uuidLibrary);
368378 registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
379+ registerGlobalObject("Messages", DependencyManager::get<MessagesClient>().data());
369380 qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue);
370381 qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue);
371−
382+
372383 // constants
373384 globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
374−
385+
375386 auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
376387 registerGlobalObject("Controller", scriptingInterface.data());
377388 UserInputMapper::registerControllerTypes(this);
389+
390+ auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
391+ registerGlobalObject("Recording", recordingInterface.data());
392+
393+ registerGlobalObject("Assets", &_assetScriptingInterface);
394+
378395 }
379396
380397 void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
@@ -387,11 +404,11 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { · 6 unmodified lines
387404 Q_ARG(QScriptValue, value));
388405 return;
389406 }
390−
407+
391408 QStringList pathToValue = valueName.split(".");
392409 int partsToGo = pathToValue.length();
393410 QScriptValue partObject = globalObject();
394−
411+
395412 for (const auto& pathPart : pathToValue) {
396413 partsToGo--;
397414 if (!partObject.property(pathPart).isValid()) {
@@ -421,7 +438,7 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { · 23 unmodified lines
421438 #ifdef THREAD_DEBUGGING
422439 qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
423440 #endif
424−
441+
425442 if (!globalObject().property(name).isValid()) {
426443 if (object) {
427444 QScriptValue value = newQObject(object);
@@ -446,7 +463,7 @@ void ScriptEngine::registerFunction(const QString& name, QScriptEngine::Function · 18 unmodified lines
446463 #ifdef THREAD_DEBUGGING
447464 qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;
448465 #endif
449−
466+
450467 QScriptValue scriptFun = newFunction(functionSignature, numArguments);
451468 globalObject().setProperty(name, scriptFun);
452469 }
@@ -465,7 +482,7 @@ void ScriptEngine::registerFunction(const QString& parent, const QString& name, · 12 unmodified lines
465482 #ifdef THREAD_DEBUGGING
466483 qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;
467484 #endif
468−
485+
469486 QScriptValue object = globalObject().property(parent);
470487 if (object.isValid()) {
471488 QScriptValue scriptFun = newFunction(functionSignature, numArguments);
@@ -490,10 +507,10 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 18 unmodified lines
490507 #ifdef THREAD_DEBUGGING
491508 qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;
492509 #endif
493−
510+
494511 QScriptValue setterFunction = newFunction(setter, 1);
495512 QScriptValue getterFunction = newFunction(getter);
496−
513+
497514 if (!parent.isNull() && !parent.isEmpty()) {
498515 QScriptValue object = globalObject().property(parent);
499516 if (object.isValid()) {
@@ -522,7 +539,7 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin · 22 unmodified lines
522539 #ifdef THREAD_DEBUGGING
523540 qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
524541 #endif
525−
542+
526543 if (!_registeredHandlers.contains(entityID)) {
527544 return;
528545 }
@@ -543,7 +560,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 14 unmodified lines
543560 qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
544561 "entityID:" << entityID << " eventName:" << eventName;
545562 #endif
546−
563+
547564 QMetaObject::invokeMethod(this, "addEventHandler",
548565 Q_ARG(const EntityItemID&, entityID),
549566 Q_ARG(const QString&, eventName),
@@ -553,7 +570,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 3 unmodified lines
553570 #ifdef THREAD_DEBUGGING
554571 qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
555572 #endif
556−
573+
557574 if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script...
558575 // Connect up ALL the handlers to the global entities object's signals.
559576 // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.)
@@ -561,7 +578,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 1 unmodified line
561578 connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) {
562579 _registeredHandlers.remove(entityID);
563580 });
564−
581+
565582 // Two common cases of event handler, differing only in argument signature.
566583 using SingleEntityHandler = std::function<void(const EntityItemID&)>;
567584 auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler {
@@ -569,37 +586,37 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 1 unmodified line
569586 forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) });
570587 };
571588 };
572−
589+
573590 using MouseHandler = std::function<void(const EntityItemID&, const MouseEvent&)>;
574591 auto makeMouseHandler = [this](QString eventName) -> MouseHandler {
575592 return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) {
576593 forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) });
577594 };
578595 };
579−
596+
580597 using CollisionHandler = std::function<void(const EntityItemID&, const EntityItemID&, const Collision&)>;
581598 auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler {
582599 return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) {
583600 forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this),
584− collisionToScriptValue(this, collision) });
601+ collisionToScriptValue(this, collision) });
585602 };
586603 };
587−
604+
588605 connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity"));
589606 connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity"));
590−
607+
591608 connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity"));
592609 connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity"));
593610 connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity"));
594−
611+
595612 connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity"));
596613 connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity"));
597614 connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity"));
598−
615+
599616 connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity"));
600617 connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity"));
601618 connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity"));
602−
619+
603620 connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity"));
604621 }
605622 if (!_registeredHandlers.contains(entityID)) {
@@ -614,7 +631,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 8 unmodified lines
614631 if (_stoppingAllScripts) {
615632 return QScriptValue(); // bail early
616633 }
617−
634+
618635 if (QThread::currentThread() != thread()) {
619636 QScriptValue result;
620637 #ifdef THREAD_DEBUGGING
@@ -628,17 +645,17 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 7 unmodified lines
628645 Q_ARG(int, lineNumber));
629646 return result;
630647 }
631−
648+
632649 // Check syntax
633650 const QScriptProgram program(sourceCode, fileName, lineNumber);
634651 if (!hasCorrectSyntax(program)) {
635652 return QScriptValue();
636653 }
637−
654+
638655 ++_evaluatesPending;
639656 const auto result = QScriptEngine::evaluate(program);
640657 --_evaluatesPending;
641−
658+
642659 const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName());
643660 if (_wantSignals) {
644661 emit evaluationFinished(result, hadUncaughtException);
@@ -650,7 +667,7 @@ void ScriptEngine::run() { · 5 unmodified lines
650667 if (_stoppingAllScripts) {
651668 return; // bail early - avoid setting state in init(), as evaluate() will bail too
652669 }
653−
670+
654671 if (!_isInitialized) {
655672 init();
656673 }
@@ -660,68 +677,68 @@ void ScriptEngine::run() { · 3 unmodified lines
660677 if (_wantSignals) {
661678 emit runningStateChanged();
662679 }
663−
680+
664681 QScriptValue result = evaluate(_scriptContents, _fileNameString);
665−
682+
666683 QElapsedTimer startTime;
667684 startTime.start();
668−
685+
669686 int thisFrame = 0;
670−
687+
671688 auto nodeList = DependencyManager::get<NodeList>();
672689 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
673−
690+
674691 qint64 lastUpdate = usecTimestampNow();
675−
692+
676693 while (!_isFinished) {
677694 int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
678695 if (usecToSleep > 0) {
679696 usleep(usecToSleep);
680697 }
681−
698+
682699 if (_isFinished) {
683700 break;
684701 }
685−
702+
686703 QCoreApplication::processEvents();
687−
704+
688705 if (_isFinished) {
689706 break;
690707 }
691−
708+
692709 if (!_isFinished && entityScriptingInterface->getEntityPacketSender()->serversExist()) {
693710 // release the queue of edit entity messages.
694711 entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages();
695−
712+
696713 // since we're in non-threaded mode, call process so that the packets are sent
697714 if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) {
698715 entityScriptingInterface->getEntityPacketSender()->process();
699716 }
700717 }
701−
718+
702719 qint64 now = usecTimestampNow();
703720 float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND;
704−
721+
705722 if (!_isFinished) {
706723 if (_wantSignals) {
707724 emit update(deltaTime);
708725 }
709726 }
710727 lastUpdate = now;
711−
728+
712729 // Debug and clear exceptions
713730 hadUncaughtExceptions(*this, _fileNameString);
714731 }
715−
732+
716733 stopAllTimers(); // make sure all our timers are stopped if the script is ending
717734 if (_wantSignals) {
718735 emit scriptEnding();
719736 }
720−
737+
721738 if (entityScriptingInterface->getEntityPacketSender()->serversExist()) {
722739 // release the queue of edit entity messages.
723740 entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages();
724−
741+
725742 // since we're in non-threaded mode, call process so that the packets are sent
726743 if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) {
727744 // wait here till the edit packet sender is completely done sending
@@ -733,18 +750,16 @@ void ScriptEngine::run() { · 5 unmodified lines
733750 // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders?
734751 }
735752 }
736−
753+
737754 if (_wantSignals) {
738755 emit finished(_fileNameString);
739756 }
740−
757+
741758 _isRunning = false;
742759 if (_wantSignals) {
743760 emit runningStateChanged();
744761 emit doneRunning();
745762 }
746−
747− _doneRunningThisScript = true;
748763 }
749764
750765 // NOTE: This is private because it must be called on the same thread that created the timers, which is why
@@ -791,13 +806,13 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM · 40 unmodified lines
791806 void ScriptEngine::timerFired() {
792807 QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
793808 QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
794−
809+
795810 if (!callingTimer->isActive()) {
796811 // this timer is done, we can kill it
797812 _timerFunctionMap.remove(callingTimer);
798813 delete callingTimer;
799814 }
800−
815+
801816 // call the associated JS function, if it exists
802817 if (timerFunction.isValid()) {
803818 timerFunction.call();
@@ -808,14 +823,14 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 4 unmodified lines
808823 // create the timer, add it to the map, and start it
809824 QTimer* newTimer = new QTimer(this);
810825 newTimer->setSingleShot(isSingleShot);
811−
826+
812827 connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
813−
828+
814829 // make sure the timer stops when the script does
815830 connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
816−
831+
817832 _timerFunctionMap.insert(newTimer, function);
818−
833+
819834 newTimer->start(intervalMS);
820835 return newTimer;
821836 }
@@ -825,7 +840,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) · 3 unmodified lines
825840 qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename();
826841 return NULL; // bail early
827842 }
828−
843+
829844 return setupTimerWithInterval(function, intervalMS, false);
830845 }
831846
@@ -834,7 +849,7 @@ QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { · 2 unmodified lines
834849 qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename();
835850 return NULL; // bail early
836851 }
837−
852+
838853 return setupTimerWithInterval(function, timeoutMS, true);
839854 }
840855
@@ -852,7 +867,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { · 11 unmodified lines
852867 if (!url.scheme().isEmpty()) {
853868 return url;
854869 }
855−
870+
856871 // we apparently weren't a fully qualified url, so, let's assume we're relative
857872 // to the original URL of our script
858873 QUrl parentURL;
@@ -865,7 +880,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { · 6 unmodified lines
865880 if (parentURL.scheme().isEmpty()) {
866881 parentURL = QUrl::fromLocalFile(_fileNameString);
867882 }
868−
883+
869884 // at this point we should have a legitimate fully qualified URL for our parent
870885 url = parentURL.resolved(url);
871886 return url;
@@ -898,9 +913,9 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 26 unmodified lines
898913 qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL;
899914 }
900915 }
901−
916+
902917 BatchLoader* loader = new BatchLoader(urls);
903−
918+
904919 auto evaluateScripts = [=](const QMap<QUrl, QString>& data) {
905920 auto parentURL = _parentURL;
906921 for (QUrl url : urls) {
@@ -919,17 +934,17 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 12 unmodified lines
919934 if (callback.isFunction()) {
920935 QScriptValue(callback).call();
921936 }
922−
937+
923938 loader->deleteLater();
924939 };
925−
940+
926941 connect(loader, &BatchLoader::finished, this, evaluateScripts);
927−
942+
928943 // If we are destroyed before the loader completes, make sure to clean it up
929944 connect(this, &QObject::destroyed, loader, &QObject::deleteLater);
930−
945+
931946 loader->start();
932−
947+
933948 if (!callback.isFunction() && !loader->isFinished()) {
934949 QEventLoop loop;
935950 QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit);
@@ -943,7 +958,7 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { · 7 unmodified lines
943958 << "includeFile:" << includeFile << "parent script:" << getFilename();
944959 return; // bail early
945960 }
946−
961+
947962 QStringList urls;
948963 urls.append(includeFile);
949964 include(urls, callback);
@@ -958,7 +973,7 @@ void ScriptEngine::load(const QString& loadFile) { · 8 unmodified lines
958973 << "loadFile:" << loadFile << "parent script:" << getFilename();
959974 return; // bail early
960975 }
961−
976+
962977 QUrl url = resolvePath(loadFile);
963978 if (_isReloading) {
964979 auto scriptCache = DependencyManager::get<ScriptCache>();
@@ -1003,7 +1018,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 38 unmodified lines
10031018 qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
10041019 "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload;
10051020 #endif
1006−
1021+
10071022 QMetaObject::invokeMethod(this, "loadEntityScript",
10081023 Q_ARG(const EntityItemID&, entityID),
10091024 Q_ARG(const QString&, entityScript),
@@ -1014,10 +1029,10 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 4 unmodified lines
10141029 qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] "
10151030 "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload;
10161031 #endif
1017−
1032+
10181033 // If we've been called our known entityScripts should not know about us..
10191034 assert(!_entityScripts.contains(entityID));
1020−
1035+
10211036 #ifdef THREAD_DEBUGGING
10221037 qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
10231038 #endif
@@ -1025,7 +1040,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 1 unmodified line
10251040 #ifdef THREAD_DEBUGGING
10261041 qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
10271042 #endif
1028−
1043+
10291044 this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);
10301045 }, forceRedownload);
10311046 }
@@ -1038,7 +1053,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 6 unmodified lines
10381053 qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
10391054 "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success;
10401055 #endif
1041−
1056+
10421057 QMetaObject::invokeMethod(this, "entityScriptContentAvailable",
10431058 Q_ARG(const EntityItemID&, entityID),
10441059 Q_ARG(const QString&, scriptOrURL),
@@ -1047,15 +1062,15 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 2 unmodified lines
10471062 Q_ARG(bool, success));
10481063 return;
10491064 }
1050−
1065+
10511066 #ifdef THREAD_DEBUGGING
10521067 qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
10531068 #endif
1054−
1069+
10551070 auto scriptCache = DependencyManager::get<ScriptCache>();
10561071 bool isFileUrl = isURL && scriptOrURL.startsWith("file://");
10571072 auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript");
1058−
1073+
10591074 QScriptProgram program(contents, fileName);
10601075 if (!hasCorrectSyntax(program)) {
10611076 if (!isFileUrl) {
@@ -1063,17 +1078,17 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 1 unmodified line
10631078 }
10641079 return; // done processing script
10651080 }
1066−
1081+
10671082 if (isURL) {
10681083 setParentURL(scriptOrURL);
10691084 }
1070−
1085+
10711086 QScriptEngine sandbox;
10721087 QScriptValue testConstructor = sandbox.evaluate(program);
10731088 if (hadUncaughtExceptions(sandbox, program.fileName())) {
10741089 return;
10751090 }
1076−
1091+
10771092 if (!testConstructor.isFunction()) {
10781093 qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n"
10791094 " NOT CONSTRUCTOR\n"
@@ -1083,13 +1098,13 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 3 unmodified lines
10831098 }
10841099 return; // done processing script
10851100 }
1086−
1101+
10871102 int64_t lastModified = 0;
10881103 if (isFileUrl) {
10891104 QString file = QUrl(scriptOrURL).toLocalFile();
10901105 lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();
10911106 }
1092−
1107+
10931108 QScriptValue entityScriptConstructor = evaluate(contents, fileName);
10941109 QScriptValue entityScriptObject = entityScriptConstructor.construct();
10951110 EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified };
@@ -1097,7 +1112,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 1 unmodified line
10971112 if (isURL) {
10981113 setParentURL("");
10991114 }
1100−
1115+
11011116 // if we got this far, then call the preload method
11021117 callEntityScriptMethod(entityID, "preload");
11031118 }
@@ -1108,7 +1123,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 4 unmodified lines
11081123 qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
11091124 "entityID:" << entityID;
11101125 #endif
1111−
1126+
11121127 QMetaObject::invokeMethod(this, "unloadEntityScript",
11131128 Q_ARG(const EntityItemID&, entityID));
11141129 return;
@@ -1117,7 +1132,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 2 unmodified lines
11171132 qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] "
11181133 "entityID:" << entityID;
11191134 #endif
1120−
1135+
11211136 if (_entityScripts.contains(entityID)) {
11221137 callEntityScriptMethod(entityID, "unload");
11231138 _entityScripts.remove(entityID);
@@ -1129,7 +1144,7 @@ void ScriptEngine::unloadAllEntityScripts() { · 5 unmodified lines
11291144 #ifdef THREAD_DEBUGGING
11301145 qDebug() << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
11311146 #endif
1132−
1147+
11331148 QMetaObject::invokeMethod(this, "unloadAllEntityScripts");
11341149 return;
11351150 }
@@ -1146,21 +1161,21 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 10 unmodified lines
11461161 if (!_entityScripts.contains(entityID)) {
11471162 return;
11481163 }
1149−
1164+
11501165 static bool recurseGuard = false;
11511166 if (recurseGuard) {
11521167 return;
11531168 }
11541169 recurseGuard = true;
1155−
1170+
11561171 EntityScriptDetails details = _entityScripts[entityID];
11571172 // Check to see if a file based script needs to be reloaded (easier debugging)
11581173 if (details.lastModified > 0) {
11591174 QString filePath = QUrl(details.scriptText).toLocalFile();
11601175 auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();
11611176 if (lastModified > details.lastModified) {
1162− qDebug() << "Reloading modified script " << details.scriptText;
1163−
1177+ qCDebug(scriptengine) << "Reloading modified script " << details.scriptText;
1178+
11641179 QFile file(filePath);
11651180 file.open(QIODevice::ReadOnly);
11661181 QString scriptContents = QTextStream(&file).readAll();
@@ -1182,7 +1197,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 15 unmodified lines
11821197 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
11831198 "entityID:" << entityID << "methodName:" << methodName;
11841199 #endif
1185−
1200+
11861201 QMetaObject::invokeMethod(this, "callEntityScriptMethod",
11871202 Q_ARG(const EntityItemID&, entityID),
11881203 Q_ARG(const QString&, methodName),
@@ -1193,7 +1208,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines
11931208 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
11941209 "entityID:" << entityID << "methodName:" << methodName;
11951210 #endif
1196−
1211+
11971212 refreshFileScript(entityID);
11981213 if (_entityScripts.contains(entityID)) {
11991214 EntityScriptDetails details = _entityScripts[entityID];
@@ -1204,7 +1219,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines
12041219 args << qScriptValueFromSequence(this, params);
12051220 entityScript.property(methodName).call(entityScript, args);
12061221 }
1207−
1222+
12081223 }
12091224 }
12101225
@@ -1214,7 +1229,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 3 unmodified lines
12141229 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
12151230 "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
12161231 #endif
1217−
1232+
12181233 QMetaObject::invokeMethod(this, "callEntityScriptMethod",
12191234 Q_ARG(const EntityItemID&, entityID),
12201235 Q_ARG(const QString&, methodName),
@@ -1225,7 +1240,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines
12251240 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
12261241 "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
12271242 #endif
1228−
1243+
12291244 refreshFileScript(entityID);
12301245 if (_entityScripts.contains(entityID)) {
12311246 EntityScriptDetails details = _entityScripts[entityID];
@@ -1246,7 +1261,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 14 unmodified lines
12461261 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
12471262 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
12481263 #endif
1249−
1264+
12501265 QMetaObject::invokeMethod(this, "callEntityScriptMethod",
12511266 Q_ARG(const EntityItemID&, entityID),
12521267 Q_ARG(const QString&, methodName),
@@ -1271,4 +1286,4 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 18 unmodified lines
12711286 entityScript.property(methodName).call(entityScript, args);
12721287 }
12731288 }
1274−}
1289+}