From 0b607fa390462ff08e3142df2ac5d5d10523c385 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 20 Feb 2015 15:28:25 -0800 Subject: [PATCH 01/31] first cut at shutting down scripts ahead of other cleanup --- interface/src/Application.cpp | 18 +- .../src/EntityTreeRenderer.cpp | 329 ++++++++++-------- .../src/EntityTreeRenderer.h | 3 + libraries/script-engine/src/ScriptEngine.cpp | 58 ++- libraries/script-engine/src/ScriptEngine.h | 10 + 5 files changed, 270 insertions(+), 148 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1211df3727..ecb74392a6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -527,12 +527,22 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : } void Application::aboutToQuit() { +qDebug() << "Application::aboutToQuit()"; _aboutToQuit = true; cleanupBeforeQuit(); } void Application::cleanupBeforeQuit() { + qDebug() << "Application::cleanupBeforeQuit() ------------ START -----------------"; + + // stop entities running scripts + _entities.shutdown(); + + // stop all running scripts + ScriptEngine::gracefullyStopAllScripts(); + + // first stop all timers directly or by invokeMethod // depending on what thread they run in locationUpdateTimer->stop(); @@ -572,6 +582,8 @@ void Application::cleanupBeforeQuit() { // destroy the AudioClient so it and its thread have a chance to go down safely DependencyManager::destroy(); + + qDebug() << "Application::cleanupBeforeQuit() ------------ DONE -----------------"; } Application::~Application() { @@ -3432,6 +3444,7 @@ void Application::clearScriptsBeforeRunning() { } void Application::saveScripts() { +qDebug() << "Application::saveScripts()"; // Saves all currently running user-loaded scripts Settings settings; settings.beginWriteArray(SETTINGS_KEY); @@ -3525,7 +3538,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri #endif QThread* workerThread = new QThread(this); - workerThread->setObjectName("Script Engine Thread"); + QString scriptEngineName = QString("Script Thread:") + scriptEngine->getFilename(); + workerThread->setObjectName(scriptEngineName); // when the worker thread is started, call our engine's run.. connect(workerThread, &QThread::started, scriptEngine, &ScriptEngine::run); @@ -3599,6 +3613,7 @@ void Application::handleScriptLoadError(const QString& scriptFilename) { } void Application::scriptFinished(const QString& scriptName) { + qDebug() << "Application::scriptFinished(), scriptName:" << scriptName; const QString& scriptURLString = QUrl(scriptName).toString(); QHash::iterator it = _scriptEnginesHash.find(scriptURLString); if (it != _scriptEnginesHash.end()) { @@ -3609,6 +3624,7 @@ void Application::scriptFinished(const QString& scriptName) { } void Application::stopAllScripts(bool restart) { + qDebug() << "Application::stopAllScripts()... restart:" << restart; // stops all current running scripts for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); it != _scriptEnginesHash.constEnd(); it++) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 975d0f515d..b0396f32d6 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -97,6 +97,27 @@ void EntityTreeRenderer::init() { connect(entityTree, &EntityTree::changingEntityID, this, &EntityTreeRenderer::changingEntityID); } +void EntityTreeRenderer::shutdown() { + _shuttingDown = true; + + /* + if (_entitiesScriptEngine) { + _entitiesScriptEngine->stop(); + + QEventLoop loop; + QObject::connect(_entitiesScriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); + + _entitiesScriptEngine->stop(); + + qDebug() << "waiting on Entities sandbox script to stop... "; + loop.exec(); + qDebug() << "done waiting... "; + + } + */ +} + + QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) { EntityItem* entity = static_cast(_tree)->findEntityByEntityItemID(entityItemID); return loadEntityScript(entity); @@ -156,6 +177,10 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) { + if (_shuttingDown) { + return QScriptValue(); // no entity... + } + if (!entity) { return QScriptValue(); // no entity... } @@ -235,7 +260,7 @@ void EntityTreeRenderer::setTree(Octree* newTree) { } void EntityTreeRenderer::update() { - if (_tree) { + if (_tree && !_shuttingDown) { EntityTree* tree = static_cast(_tree); tree->update(); @@ -258,7 +283,7 @@ void EntityTreeRenderer::update() { } void EntityTreeRenderer::checkEnterLeaveEntities() { - if (_tree) { + if (_tree && !_shuttingDown) { _tree->lockForWrite(); // so that our scripts can do edits if they want glm::vec3 avatarPosition = _viewState->getAvatarPosition() / (float) TREE_SCALE; @@ -309,7 +334,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { } void EntityTreeRenderer::leaveAllEntities() { - if (_tree) { + if (_tree && !_shuttingDown) { _tree->lockForWrite(); // so that our scripts can do edits if they want // for all of our previous containing entities, if they are no longer containing then send them a leave event @@ -330,7 +355,7 @@ void EntityTreeRenderer::leaveAllEntities() { } } void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { - if (_tree) { + if (_tree && !_shuttingDown) { Model::startScene(renderSide); RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -700,179 +725,193 @@ QScriptValueList EntityTreeRenderer::createEntityArgs(const EntityItemID& entity } void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { - PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); + if (_tree && !_shuttingDown) { + PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); + PickRay ray = _viewState->computePickRay(event->x(), event->y()); - bool precisionPicking = !_dontDoPrecisionPicking; - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); - if (rayPickResult.intersects) { - //qDebug() << "mousePressEvent over entity:" << rayPickResult.entityID; - emit mousePressOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + bool precisionPicking = !_dontDoPrecisionPicking; + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); + if (rayPickResult.intersects) { + //qDebug() << "mousePressEvent over entity:" << rayPickResult.entityID; + emit mousePressOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); - QScriptValue entityScript = loadEntityScript(rayPickResult.entity); - if (entityScript.property("mousePressOnEntity").isValid()) { - entityScript.property("mousePressOnEntity").call(entityScript, entityScriptArgs); - } + QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); + QScriptValue entityScript = loadEntityScript(rayPickResult.entity); + if (entityScript.property("mousePressOnEntity").isValid()) { + entityScript.property("mousePressOnEntity").call(entityScript, entityScriptArgs); + } - _currentClickingOnEntityID = rayPickResult.entityID; - emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - if (entityScript.property("clickDownOnEntity").isValid()) { - entityScript.property("clickDownOnEntity").call(entityScript, entityScriptArgs); + _currentClickingOnEntityID = rayPickResult.entityID; + emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); + if (entityScript.property("clickDownOnEntity").isValid()) { + entityScript.property("clickDownOnEntity").call(entityScript, entityScriptArgs); + } } + _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEventValid = true; } - _lastMouseEvent = MouseEvent(*event, deviceID); - _lastMouseEventValid = true; } void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { - PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent"); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); - bool precisionPicking = !_dontDoPrecisionPicking; - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); - if (rayPickResult.intersects) { - //qDebug() << "mouseReleaseEvent over entity:" << rayPickResult.entityID; - emit mouseReleaseOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + if (_tree && !_shuttingDown) { + PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent"); + PickRay ray = _viewState->computePickRay(event->x(), event->y()); + bool precisionPicking = !_dontDoPrecisionPicking; + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); + if (rayPickResult.intersects) { + //qDebug() << "mouseReleaseEvent over entity:" << rayPickResult.entityID; + emit mouseReleaseOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); - QScriptValue entityScript = loadEntityScript(rayPickResult.entity); - if (entityScript.property("mouseReleaseOnEntity").isValid()) { - entityScript.property("mouseReleaseOnEntity").call(entityScript, entityScriptArgs); + QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); + QScriptValue entityScript = loadEntityScript(rayPickResult.entity); + if (entityScript.property("mouseReleaseOnEntity").isValid()) { + entityScript.property("mouseReleaseOnEntity").call(entityScript, entityScriptArgs); + } } - } - // Even if we're no longer intersecting with an entity, if we started clicking on it, and now - // we're releasing the button, then this is considered a clickOn event - if (!_currentClickingOnEntityID.isInvalidID()) { - emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); + // Even if we're no longer intersecting with an entity, if we started clicking on it, and now + // we're releasing the button, then this is considered a clickOn event + if (!_currentClickingOnEntityID.isInvalidID()) { + emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); - QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); - if (currentClickingEntity.property("clickReleaseOnEntity").isValid()) { - currentClickingEntity.property("clickReleaseOnEntity").call(currentClickingEntity, currentClickingEntityArgs); + QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); + QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); + if (currentClickingEntity.property("clickReleaseOnEntity").isValid()) { + currentClickingEntity.property("clickReleaseOnEntity").call(currentClickingEntity, currentClickingEntityArgs); + } } - } - // makes it the unknown ID, we just released so we can't be clicking on anything - _currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); - _lastMouseEvent = MouseEvent(*event, deviceID); - _lastMouseEventValid = true; + // makes it the unknown ID, we just released so we can't be clicking on anything + _currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); + _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEventValid = true; + } } void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { - PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent"); + if (_tree && !_shuttingDown) { + PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent"); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); + PickRay ray = _viewState->computePickRay(event->x(), event->y()); - bool precisionPicking = false; // for mouse moves we do not do precision picking - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); - if (rayPickResult.intersects) { - QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); + bool precisionPicking = false; // for mouse moves we do not do precision picking + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); + if (rayPickResult.intersects) { + QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); - // load the entity script if needed... - QScriptValue entityScript = loadEntityScript(rayPickResult.entity); - if (entityScript.property("mouseMoveEvent").isValid()) { - entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); - } + // load the entity script if needed... + QScriptValue entityScript = loadEntityScript(rayPickResult.entity); + if (entityScript.property("mouseMoveEvent").isValid()) { + entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); + } - //qDebug() << "mouseMoveEvent over entity:" << rayPickResult.entityID; - emit mouseMoveOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - if (entityScript.property("mouseMoveOnEntity").isValid()) { - entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); - } + //qDebug() << "mouseMoveEvent over entity:" << rayPickResult.entityID; + emit mouseMoveOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + if (entityScript.property("mouseMoveOnEntity").isValid()) { + entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); + } - // handle the hover logic... + // handle the hover logic... - // if we were previously hovering over an entity, and this new entity is not the same as our previous entity - // then we need to send the hover leave. - if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) { - emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); + // if we were previously hovering over an entity, and this new entity is not the same as our previous entity + // then we need to send the hover leave. + if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) { + emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); - QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); + QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); - QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); - if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { - currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); - } - } - - // If the new hover entity does not match the previous hover entity then we are entering the new one - // this is true if the _currentHoverOverEntityID is known or unknown - if (rayPickResult.entityID != _currentHoverOverEntityID) { - emit hoverEnterEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - if (entityScript.property("hoverEnterEntity").isValid()) { - entityScript.property("hoverEnterEntity").call(entityScript, entityScriptArgs); - } - } - - // and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and - // we should send our hover over event - emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - if (entityScript.property("hoverOverEntity").isValid()) { - entityScript.property("hoverOverEntity").call(entityScript, entityScriptArgs); - } - - // remember what we're hovering over - _currentHoverOverEntityID = rayPickResult.entityID; - - } else { - // handle the hover logic... - // if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to - // send the hover leave for our previous entity - if (!_currentHoverOverEntityID.isInvalidID()) { - emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); - - QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); - - QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); - if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { - currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); + QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); + if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { + currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); + } } - _currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID + // If the new hover entity does not match the previous hover entity then we are entering the new one + // this is true if the _currentHoverOverEntityID is known or unknown + if (rayPickResult.entityID != _currentHoverOverEntityID) { + emit hoverEnterEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + if (entityScript.property("hoverEnterEntity").isValid()) { + entityScript.property("hoverEnterEntity").call(entityScript, entityScriptArgs); + } + } + + // and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and + // we should send our hover over event + emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + if (entityScript.property("hoverOverEntity").isValid()) { + entityScript.property("hoverOverEntity").call(entityScript, entityScriptArgs); + } + + // remember what we're hovering over + _currentHoverOverEntityID = rayPickResult.entityID; + + } else { + // handle the hover logic... + // if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to + // send the hover leave for our previous entity + if (!_currentHoverOverEntityID.isInvalidID()) { + emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); + + QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); + + QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); + if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { + currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); + } + + _currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID + } } - } - // Even if we're no longer intersecting with an entity, if we started clicking on an entity and we have - // not yet released the hold then this is still considered a holdingClickOnEntity event - if (!_currentClickingOnEntityID.isInvalidID()) { - emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); + // Even if we're no longer intersecting with an entity, if we started clicking on an entity and we have + // not yet released the hold then this is still considered a holdingClickOnEntity event + if (!_currentClickingOnEntityID.isInvalidID()) { + emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); + QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); - QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); - if (currentClickingEntity.property("holdingClickOnEntity").isValid()) { - currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs); + QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); + if (currentClickingEntity.property("holdingClickOnEntity").isValid()) { + currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs); + } } + _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEventValid = true; } - _lastMouseEvent = MouseEvent(*event, deviceID); - _lastMouseEventValid = true; } void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { - checkAndCallUnload(entityID); + if (_tree && !_shuttingDown) { + checkAndCallUnload(entityID); + } _entityScripts.remove(entityID); } void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID) { - checkAndCallUnload(entityID); + if (_tree && !_shuttingDown) { + checkAndCallUnload(entityID); + } checkAndCallPreload(entityID); } void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) { - // load the entity script if needed... - QScriptValue entityScript = loadEntityScript(entityID); - if (entityScript.property("preload").isValid()) { - QScriptValueList entityArgs = createEntityArgs(entityID); - entityScript.property("preload").call(entityScript, entityArgs); + if (_tree && !_shuttingDown) { + // load the entity script if needed... + QScriptValue entityScript = loadEntityScript(entityID); + if (entityScript.property("preload").isValid()) { + QScriptValueList entityArgs = createEntityArgs(entityID); + entityScript.property("preload").call(entityScript, entityArgs); + } } } void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { - QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID); - if (entityScript.property("unload").isValid()) { - QScriptValueList entityArgs = createEntityArgs(entityID); - entityScript.property("unload").call(entityScript, entityArgs); + if (_tree && !_shuttingDown) { + QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID); + if (entityScript.property("unload").isValid()) { + QScriptValueList entityArgs = createEntityArgs(entityID); + entityScript.property("unload").call(entityScript, entityArgs); + } } } @@ -887,22 +926,24 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - QScriptValue entityScriptA = loadEntityScript(idA); - if (entityScriptA.property("collisionWithEntity").isValid()) { - QScriptValueList args; - args << idA.toScriptValue(_entitiesScriptEngine); - args << idB.toScriptValue(_entitiesScriptEngine); - args << collisionToScriptValue(_entitiesScriptEngine, collision); - entityScriptA.property("collisionWithEntity").call(entityScriptA, args); - } + if (_tree && !_shuttingDown) { + QScriptValue entityScriptA = loadEntityScript(idA); + if (entityScriptA.property("collisionWithEntity").isValid()) { + QScriptValueList args; + args << idA.toScriptValue(_entitiesScriptEngine); + args << idB.toScriptValue(_entitiesScriptEngine); + args << collisionToScriptValue(_entitiesScriptEngine, collision); + entityScriptA.property("collisionWithEntity").call(entityScriptA, args); + } - QScriptValue entityScriptB = loadEntityScript(idB); - if (entityScriptB.property("collisionWithEntity").isValid()) { - QScriptValueList args; - args << idB.toScriptValue(_entitiesScriptEngine); - args << idA.toScriptValue(_entitiesScriptEngine); - args << collisionToScriptValue(_entitiesScriptEngine, collision); - entityScriptB.property("collisionWithEntity").call(entityScriptA, args); + QScriptValue entityScriptB = loadEntityScript(idB); + if (entityScriptB.property("collisionWithEntity").isValid()) { + QScriptValueList args; + args << idB.toScriptValue(_entitiesScriptEngine); + args << idA.toScriptValue(_entitiesScriptEngine); + args << collisionToScriptValue(_entitiesScriptEngine, collision); + entityScriptB.property("collisionWithEntity").call(entityScriptA, args); + } } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 3826a80238..0da85f360b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -46,6 +46,7 @@ public: virtual int getBoundaryLevelAdjust() const; virtual void setTree(Octree* newTree); + void shutdown(); void update(); EntityTree* getTree() { return static_cast(_tree); } @@ -154,6 +155,8 @@ private: bool _displayModelElementProxy; bool _dontDoPrecisionPicking; + bool _shuttingDown = false; + }; #endif // hifi_EntityTreeRenderer_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 0956374238..63ecea4254 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -94,8 +94,45 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _isUserLoaded(false), _arrayBufferClass(new ArrayBufferClass(this)) { + _allKnownScriptEngines.insert(this); } +ScriptEngine::~ScriptEngine() { + qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::~ScriptEngine() " << getFilename(); + _allKnownScriptEngines.remove(this); +} + +QSet ScriptEngine::_allKnownScriptEngines; + +void ScriptEngine::gracefullyStopAllScripts() { + qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- START ------------------"; + foreach(ScriptEngine* scriptEngine, _allKnownScriptEngines) { + if (scriptEngine->isRunning()) { + qDebug() << "scriptEngine still alive:" << scriptEngine->getFilename() << "[" << scriptEngine << "]"; + + QEventLoop loop; + QObject::connect(scriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); + + scriptEngine->stop(); + + qDebug() << "waiting on script to stop... "; + loop.exec(); + qDebug() << "done waiting... "; + } + } + qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- DONE ------------------"; +} + +QString ScriptEngine::getFilename() const { + QStringList fileNameParts = _fileNameString.split("/"); + QString lastPart; + if (!fileNameParts.isEmpty()) { + lastPart = fileNameParts.last(); + } + return lastPart; +} + + void ScriptEngine::setIsAvatar(bool isAvatar) { _isAvatar = isAvatar; @@ -364,16 +401,18 @@ void ScriptEngine::run() { } if (_isFinished) { + qDebug() << "ScriptEngine::run()... while() about to break " << getFilename(); break; } QCoreApplication::processEvents(); if (_isFinished) { + qDebug() << "ScriptEngine::run()... while() about to break " << getFilename(); break; } - if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) { + if (!_isFinished && _entityScriptingInterface.getEntityPacketSender()->serversExist()) { // release the queue of edit entity messages. _entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages(); @@ -383,7 +422,7 @@ void ScriptEngine::run() { } } - if (_isAvatar && _avatarData) { + if (!_isFinished && _isAvatar && _avatarData) { const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * AudioConstants::SAMPLE_RATE) / (1000 * 1000)) + 0.5); @@ -493,9 +532,13 @@ void ScriptEngine::run() { clearExceptions(); } - emit update(deltaTime); + if (!_isFinished) { + //qDebug() << "ScriptEngine::run()... about to emit update() _scriptName:" << _scriptName << "_fileNameString:" << _fileNameString << "_isFinished:" << _isFinished; + emit update(deltaTime); + } lastUpdate = now; } + qDebug() << "ScriptEngine::run()... about to emit scriptEnding() " << getFilename(); emit scriptEnding(); // kill the avatar identity timer @@ -513,16 +556,25 @@ void ScriptEngine::run() { // If we were on a thread, then wait till it's done if (thread()) { + qDebug() << "ScriptEngine::run()... about to call thread()->quit() " << getFilename(); thread()->quit(); } + qDebug() << "ScriptEngine::run()... about to emit finished() " << getFilename(); emit finished(_fileNameString); _isRunning = false; + + qDebug() << "ScriptEngine::run()... about to emit runningStateChanged() " << getFilename(); emit runningStateChanged(); + + qDebug() << "ScriptEngine::run()... about to emit doneRunning() " << getFilename(); + emit doneRunning(); + qDebug() << "ScriptEngine::run()... DONE WITH run()... " << getFilename(); } void ScriptEngine::stop() { + qDebug() << "ScriptEngine::stop()... " << getFilename(); _isFinished = true; emit runningStateChanged(); } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index f2911842e6..f3289a8c70 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -43,6 +43,8 @@ public: const QString& fileNameString = QString(""), AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); + ~ScriptEngine(); + /// Access the EntityScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener static EntityScriptingInterface* getEntityScriptingInterface() { return &_entityScriptingInterface; } @@ -88,6 +90,10 @@ public: bool isUserLoaded() const { return _isUserLoaded; } void setParentURL(const QString& parentURL) { _parentURL = parentURL; } + + QString getFilename() const; + + static void gracefullyStopAllScripts(); public slots: void loadURL(const QUrl& scriptURL); @@ -118,6 +124,7 @@ signals: void runningStateChanged(); void evaluationFinished(QScriptValue result, bool isException); void loadScript(const QString& scriptName, bool isUserLoaded); + void doneRunning(); protected: QString _scriptContents; @@ -156,6 +163,9 @@ private: QHash _outgoingScriptAudioSequenceNumbers; private slots: void handleScriptDownload(); + +private: + static QSet _allKnownScriptEngines; }; #endif // hifi_ScriptEngine_h From b219937902d30e706eeb40463a02f5f203b592c8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 20 Feb 2015 15:46:11 -0800 Subject: [PATCH 02/31] switch known scripts iterator --- libraries/script-engine/src/ScriptEngine.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 63ecea4254..e4401bd4b4 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -106,7 +106,12 @@ QSet ScriptEngine::_allKnownScriptEngines; void ScriptEngine::gracefullyStopAllScripts() { qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- START ------------------"; - foreach(ScriptEngine* scriptEngine, _allKnownScriptEngines) { + + QSet::const_iterator i = _allKnownScriptEngines.constBegin(); + while (i != _allKnownScriptEngines.constEnd()) { + ScriptEngine* scriptEngine = *i; + qDebug() << scriptEngine; + if (scriptEngine->isRunning()) { qDebug() << "scriptEngine still alive:" << scriptEngine->getFilename() << "[" << scriptEngine << "]"; @@ -119,6 +124,8 @@ void ScriptEngine::gracefullyStopAllScripts() { loop.exec(); qDebug() << "done waiting... "; } + + ++i; } qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- DONE ------------------"; } From 8c4474b2d0a88d083e330f50856b2306d15f6be7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 20 Feb 2015 17:55:04 -0800 Subject: [PATCH 03/31] more hacking --- interface/src/Application.cpp | 4 ++-- libraries/script-engine/src/ScriptEngine.cpp | 18 +++++++++++------- libraries/script-engine/src/ScriptEngine.h | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ecb74392a6..e7b71afd93 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -540,7 +540,7 @@ void Application::cleanupBeforeQuit() { _entities.shutdown(); // stop all running scripts - ScriptEngine::gracefullyStopAllScripts(); + ScriptEngine::gracefullyStopAllScripts(this); // first stop all timers directly or by invokeMethod @@ -3545,7 +3545,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri connect(workerThread, &QThread::started, scriptEngine, &ScriptEngine::run); // when the thread is terminated, add both scriptEngine and thread to the deleteLater queue - connect(scriptEngine, SIGNAL(finished(const QString&)), scriptEngine, SLOT(deleteLater())); + connect(scriptEngine, SIGNAL(doneRunning()), scriptEngine, SLOT(deleteLater())); connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); // when the application is about to quit, stop our script engine so it unwinds properly diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e4401bd4b4..5cbf0b1149 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -94,6 +94,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _isUserLoaded(false), _arrayBufferClass(new ArrayBufferClass(this)) { + qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::ScriptEngine() " << getFilename() << "[" << this << "]"; _allKnownScriptEngines.insert(this); } @@ -104,28 +105,31 @@ ScriptEngine::~ScriptEngine() { QSet ScriptEngine::_allKnownScriptEngines; -void ScriptEngine::gracefullyStopAllScripts() { +void ScriptEngine::gracefullyStopAllScripts(QObject* application) { qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- START ------------------"; - QSet::const_iterator i = _allKnownScriptEngines.constBegin(); - while (i != _allKnownScriptEngines.constEnd()) { - ScriptEngine* scriptEngine = *i; - qDebug() << scriptEngine; + + QSetIterator i(_allKnownScriptEngines); + while (i.hasNext()) { + ScriptEngine* scriptEngine = i.next(); + qDebug() << (void*)scriptEngine; if (scriptEngine->isRunning()) { qDebug() << "scriptEngine still alive:" << scriptEngine->getFilename() << "[" << scriptEngine << "]"; QEventLoop loop; QObject::connect(scriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); + + scriptEngine->disconnect(application); scriptEngine->stop(); qDebug() << "waiting on script to stop... "; loop.exec(); qDebug() << "done waiting... "; + } else { + qDebug() << "WARNING! scriptEngine [" << (void*)scriptEngine << "] still in _allKnownScriptEngines but not running??? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"; } - - ++i; } qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- DONE ------------------"; } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index f3289a8c70..1bd07ba220 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -93,7 +93,7 @@ public: QString getFilename() const; - static void gracefullyStopAllScripts(); + static void gracefullyStopAllScripts(QObject* application); public slots: void loadURL(const QUrl& scriptURL); From e3de994c4ad9276413a205bbcc55d499e5b2b264 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 20 Feb 2015 18:42:02 -0800 Subject: [PATCH 04/31] more hacking --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 8 ++++++-- libraries/script-engine/src/ScriptEngine.cpp | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index b0396f32d6..c81599dd33 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -61,8 +61,12 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf EntityTreeRenderer::~EntityTreeRenderer() { // NOTE: we don't need to delete _entitiesScriptEngine because it's owned by the application and gets cleaned up // automatically but we do need to delete our sandbox script engine. - delete _sandboxScriptEngine; - _sandboxScriptEngine = NULL; + + if (_sandboxScriptEngine) { + qDebug() << "EntityTreeRenderer::~EntityTreeRenderer() delete _sandboxScriptEngine!!!!!"; + delete _sandboxScriptEngine; + _sandboxScriptEngine = NULL; + } } void EntityTreeRenderer::clear() { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 5cbf0b1149..9ec76e38b2 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -109,7 +109,7 @@ void ScriptEngine::gracefullyStopAllScripts(QObject* application) { qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- START ------------------"; - QSetIterator i(_allKnownScriptEngines); + QMutableSetIterator i(_allKnownScriptEngines); while (i.hasNext()) { ScriptEngine* scriptEngine = i.next(); qDebug() << (void*)scriptEngine; @@ -121,7 +121,6 @@ void ScriptEngine::gracefullyStopAllScripts(QObject* application) { QObject::connect(scriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); scriptEngine->disconnect(application); - scriptEngine->stop(); qDebug() << "waiting on script to stop... "; From 2e7a43a7fb73ee46163083702697a07f880b10fb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 20 Feb 2015 18:47:47 -0800 Subject: [PATCH 05/31] more hacking --- interface/src/Application.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e7b71afd93..2fe11608a5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -587,27 +587,51 @@ void Application::cleanupBeforeQuit() { } Application::~Application() { - EntityTree* tree = _entities.getTree(); - tree->lockForWrite(); - _entities.getTree()->setSimulation(NULL); - tree->unlock(); + qDebug() << "Application::~Application() ------------ START -----------------"; + + qDebug() << "Application::~Application() line:" << __LINE__; + EntityTree* tree = _entities.getTree(); + qDebug() << "Application::~Application() line:" << __LINE__; + tree->lockForWrite(); + qDebug() << "Application::~Application() line:" << __LINE__; + _entities.getTree()->setSimulation(NULL); + qDebug() << "Application::~Application() line:" << __LINE__; + tree->unlock(); + qDebug() << "Application::~Application() line:" << __LINE__; + + qDebug() << "Application::~Application() line:" << __LINE__; qInstallMessageHandler(NULL); + qDebug() << "Application::~Application() line:" << __LINE__; // ask the datagram processing thread to quit and wait until it is done + qDebug() << "Application::~Application() line:" << __LINE__; _nodeThread->quit(); + qDebug() << "Application::~Application() line:" << __LINE__; _nodeThread->wait(); + qDebug() << "Application::~Application() line:" << __LINE__; + qDebug() << "Application::~Application() line:" << __LINE__; _octreeProcessor.terminate(); + qDebug() << "Application::~Application() line:" << __LINE__; _entityEditSender.terminate(); + qDebug() << "Application::~Application() line:" << __LINE__; + qDebug() << "Application::~Application() line:" << __LINE__; Menu::getInstance()->deleteLater(); + qDebug() << "Application::~Application() line:" << __LINE__; + qDebug() << "Application::~Application() line:" << __LINE__; _myAvatar = NULL; + qDebug() << "Application::~Application() line:" << __LINE__; + qDebug() << "Application::~Application() line:" << __LINE__; ModelEntityItem::cleanupLoadedAnimations() ; + qDebug() << "Application::~Application() line:" << __LINE__; + qDebug() << "Application::~Application() line:" << __LINE__; DependencyManager::destroy(); + qDebug() << "Application::~Application() line:" << __LINE__; qDebug() << "start destroying ResourceCaches Application::~Application() line:" << __LINE__; DependencyManager::destroy(); @@ -616,6 +640,7 @@ Application::~Application() { DependencyManager::destroy(); DependencyManager::destroy(); qDebug() << "done destroying ResourceCaches Application::~Application() line:" << __LINE__; + qDebug() << "Application::~Application() ------------ DONE -----------------"; } void Application::initializeGL() { From d32fc645e80933634ce7a774f5cc68d8b05b165d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 23 Feb 2015 09:10:15 -0800 Subject: [PATCH 06/31] remove some dead code, added a debugging notes comment --- .../src/EntityTreeRenderer.cpp | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c81599dd33..7a089eee5f 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -63,6 +63,11 @@ EntityTreeRenderer::~EntityTreeRenderer() { // automatically but we do need to delete our sandbox script engine. if (_sandboxScriptEngine) { + // NOTE: is it possible this is a problem? I think that we hook the script engine object up to a deleteLater() + // call inside of registerScriptEngineWithApplicationServices() but do we not call that for _sandboxScriptEngine??? + // this _sandboxScriptEngine implementation is confusing and potentially error prone because it's not a full fledged + // ScriptEngine that has been fully connected. We did this so that scripts that were ill-formed could be evaluated + // but not execute against the application. qDebug() << "EntityTreeRenderer::~EntityTreeRenderer() delete _sandboxScriptEngine!!!!!"; delete _sandboxScriptEngine; _sandboxScriptEngine = NULL; @@ -103,22 +108,6 @@ void EntityTreeRenderer::init() { void EntityTreeRenderer::shutdown() { _shuttingDown = true; - - /* - if (_entitiesScriptEngine) { - _entitiesScriptEngine->stop(); - - QEventLoop loop; - QObject::connect(_entitiesScriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); - - _entitiesScriptEngine->stop(); - - qDebug() << "waiting on Entities sandbox script to stop... "; - loop.exec(); - qDebug() << "done waiting... "; - - } - */ } From e5ef61e27ee15b0cd7ad3d0409b374bf7ba3122b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 23 Feb 2015 09:23:15 -0800 Subject: [PATCH 07/31] simplifying the change --- .../src/EntityTreeRenderer.cpp | 334 +++++++++--------- 1 file changed, 173 insertions(+), 161 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 7a089eee5f..18813de519 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -718,159 +718,168 @@ QScriptValueList EntityTreeRenderer::createEntityArgs(const EntityItemID& entity } void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { - if (_tree && !_shuttingDown) { - PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); - - bool precisionPicking = !_dontDoPrecisionPicking; - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); - if (rayPickResult.intersects) { - //qDebug() << "mousePressEvent over entity:" << rayPickResult.entityID; - emit mousePressOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - - QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); - QScriptValue entityScript = loadEntityScript(rayPickResult.entity); - if (entityScript.property("mousePressOnEntity").isValid()) { - entityScript.property("mousePressOnEntity").call(entityScript, entityScriptArgs); - } - - _currentClickingOnEntityID = rayPickResult.entityID; - emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - if (entityScript.property("clickDownOnEntity").isValid()) { - entityScript.property("clickDownOnEntity").call(entityScript, entityScriptArgs); - } - } - _lastMouseEvent = MouseEvent(*event, deviceID); - _lastMouseEventValid = true; + // If we don't have a tree, or we're in the process of shutting down, then don't + // process these events. + if (!_tree || _shuttingDown) { + return; } + PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); + PickRay ray = _viewState->computePickRay(event->x(), event->y()); + + bool precisionPicking = !_dontDoPrecisionPicking; + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); + if (rayPickResult.intersects) { + //qDebug() << "mousePressEvent over entity:" << rayPickResult.entityID; + emit mousePressOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + + QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); + QScriptValue entityScript = loadEntityScript(rayPickResult.entity); + if (entityScript.property("mousePressOnEntity").isValid()) { + entityScript.property("mousePressOnEntity").call(entityScript, entityScriptArgs); + } + + _currentClickingOnEntityID = rayPickResult.entityID; + emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); + if (entityScript.property("clickDownOnEntity").isValid()) { + entityScript.property("clickDownOnEntity").call(entityScript, entityScriptArgs); + } + } + _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEventValid = true; } void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { - if (_tree && !_shuttingDown) { - PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent"); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); - bool precisionPicking = !_dontDoPrecisionPicking; - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); - if (rayPickResult.intersects) { - //qDebug() << "mouseReleaseEvent over entity:" << rayPickResult.entityID; - emit mouseReleaseOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - - QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); - QScriptValue entityScript = loadEntityScript(rayPickResult.entity); - if (entityScript.property("mouseReleaseOnEntity").isValid()) { - entityScript.property("mouseReleaseOnEntity").call(entityScript, entityScriptArgs); - } - } - - // Even if we're no longer intersecting with an entity, if we started clicking on it, and now - // we're releasing the button, then this is considered a clickOn event - if (!_currentClickingOnEntityID.isInvalidID()) { - emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - - QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); - QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); - if (currentClickingEntity.property("clickReleaseOnEntity").isValid()) { - currentClickingEntity.property("clickReleaseOnEntity").call(currentClickingEntity, currentClickingEntityArgs); - } - } - - // makes it the unknown ID, we just released so we can't be clicking on anything - _currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); - _lastMouseEvent = MouseEvent(*event, deviceID); - _lastMouseEventValid = true; + // If we don't have a tree, or we're in the process of shutting down, then don't + // process these events. + if (!_tree || _shuttingDown) { + return; } + PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent"); + PickRay ray = _viewState->computePickRay(event->x(), event->y()); + bool precisionPicking = !_dontDoPrecisionPicking; + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); + if (rayPickResult.intersects) { + //qDebug() << "mouseReleaseEvent over entity:" << rayPickResult.entityID; + emit mouseReleaseOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + + QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); + QScriptValue entityScript = loadEntityScript(rayPickResult.entity); + if (entityScript.property("mouseReleaseOnEntity").isValid()) { + entityScript.property("mouseReleaseOnEntity").call(entityScript, entityScriptArgs); + } + } + + // Even if we're no longer intersecting with an entity, if we started clicking on it, and now + // we're releasing the button, then this is considered a clickOn event + if (!_currentClickingOnEntityID.isInvalidID()) { + emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); + + QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); + QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); + if (currentClickingEntity.property("clickReleaseOnEntity").isValid()) { + currentClickingEntity.property("clickReleaseOnEntity").call(currentClickingEntity, currentClickingEntityArgs); + } + } + + // makes it the unknown ID, we just released so we can't be clicking on anything + _currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); + _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEventValid = true; } void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { - if (_tree && !_shuttingDown) { - PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent"); - - PickRay ray = _viewState->computePickRay(event->x(), event->y()); - - bool precisionPicking = false; // for mouse moves we do not do precision picking - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); - if (rayPickResult.intersects) { - QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); - - // load the entity script if needed... - QScriptValue entityScript = loadEntityScript(rayPickResult.entity); - if (entityScript.property("mouseMoveEvent").isValid()) { - entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); - } - - //qDebug() << "mouseMoveEvent over entity:" << rayPickResult.entityID; - emit mouseMoveOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - if (entityScript.property("mouseMoveOnEntity").isValid()) { - entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); - } - - // handle the hover logic... - - // if we were previously hovering over an entity, and this new entity is not the same as our previous entity - // then we need to send the hover leave. - if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) { - emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); - - QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); - - QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); - if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { - currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); - } - } - - // If the new hover entity does not match the previous hover entity then we are entering the new one - // this is true if the _currentHoverOverEntityID is known or unknown - if (rayPickResult.entityID != _currentHoverOverEntityID) { - emit hoverEnterEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - if (entityScript.property("hoverEnterEntity").isValid()) { - entityScript.property("hoverEnterEntity").call(entityScript, entityScriptArgs); - } - } - - // and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and - // we should send our hover over event - emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); - if (entityScript.property("hoverOverEntity").isValid()) { - entityScript.property("hoverOverEntity").call(entityScript, entityScriptArgs); - } - - // remember what we're hovering over - _currentHoverOverEntityID = rayPickResult.entityID; - - } else { - // handle the hover logic... - // if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to - // send the hover leave for our previous entity - if (!_currentHoverOverEntityID.isInvalidID()) { - emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); - - QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); - - QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); - if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { - currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); - } - - _currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID - } - } - - // Even if we're no longer intersecting with an entity, if we started clicking on an entity and we have - // not yet released the hold then this is still considered a holdingClickOnEntity event - if (!_currentClickingOnEntityID.isInvalidID()) { - emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); - - QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); - - QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); - if (currentClickingEntity.property("holdingClickOnEntity").isValid()) { - currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs); - } - } - _lastMouseEvent = MouseEvent(*event, deviceID); - _lastMouseEventValid = true; + // If we don't have a tree, or we're in the process of shutting down, then don't + // process these events. + if (!_tree || _shuttingDown) { + return; } + PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent"); + + PickRay ray = _viewState->computePickRay(event->x(), event->y()); + + bool precisionPicking = false; // for mouse moves we do not do precision picking + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); + if (rayPickResult.intersects) { + QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); + + // load the entity script if needed... + QScriptValue entityScript = loadEntityScript(rayPickResult.entity); + if (entityScript.property("mouseMoveEvent").isValid()) { + entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); + } + + //qDebug() << "mouseMoveEvent over entity:" << rayPickResult.entityID; + emit mouseMoveOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + if (entityScript.property("mouseMoveOnEntity").isValid()) { + entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); + } + + // handle the hover logic... + + // if we were previously hovering over an entity, and this new entity is not the same as our previous entity + // then we need to send the hover leave. + if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) { + emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); + + QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); + + QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); + if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { + currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); + } + } + + // If the new hover entity does not match the previous hover entity then we are entering the new one + // this is true if the _currentHoverOverEntityID is known or unknown + if (rayPickResult.entityID != _currentHoverOverEntityID) { + emit hoverEnterEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + if (entityScript.property("hoverEnterEntity").isValid()) { + entityScript.property("hoverEnterEntity").call(entityScript, entityScriptArgs); + } + } + + // and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and + // we should send our hover over event + emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); + if (entityScript.property("hoverOverEntity").isValid()) { + entityScript.property("hoverOverEntity").call(entityScript, entityScriptArgs); + } + + // remember what we're hovering over + _currentHoverOverEntityID = rayPickResult.entityID; + + } else { + // handle the hover logic... + // if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to + // send the hover leave for our previous entity + if (!_currentHoverOverEntityID.isInvalidID()) { + emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); + + QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); + + QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); + if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { + currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); + } + + _currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID + } + } + + // Even if we're no longer intersecting with an entity, if we started clicking on an entity and we have + // not yet released the hold then this is still considered a holdingClickOnEntity event + if (!_currentClickingOnEntityID.isInvalidID()) { + emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); + + QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); + + QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); + if (currentClickingEntity.property("holdingClickOnEntity").isValid()) { + currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs); + } + } + _lastMouseEvent = MouseEvent(*event, deviceID); + _lastMouseEventValid = true; } void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { @@ -919,24 +928,27 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - if (_tree && !_shuttingDown) { - QScriptValue entityScriptA = loadEntityScript(idA); - if (entityScriptA.property("collisionWithEntity").isValid()) { - QScriptValueList args; - args << idA.toScriptValue(_entitiesScriptEngine); - args << idB.toScriptValue(_entitiesScriptEngine); - args << collisionToScriptValue(_entitiesScriptEngine, collision); - entityScriptA.property("collisionWithEntity").call(entityScriptA, args); - } + // If we don't have a tree, or we're in the process of shutting down, then don't + // process these events. + if (!_tree || _shuttingDown) { + return; + } + QScriptValue entityScriptA = loadEntityScript(idA); + if (entityScriptA.property("collisionWithEntity").isValid()) { + QScriptValueList args; + args << idA.toScriptValue(_entitiesScriptEngine); + args << idB.toScriptValue(_entitiesScriptEngine); + args << collisionToScriptValue(_entitiesScriptEngine, collision); + entityScriptA.property("collisionWithEntity").call(entityScriptA, args); + } - QScriptValue entityScriptB = loadEntityScript(idB); - if (entityScriptB.property("collisionWithEntity").isValid()) { - QScriptValueList args; - args << idB.toScriptValue(_entitiesScriptEngine); - args << idA.toScriptValue(_entitiesScriptEngine); - args << collisionToScriptValue(_entitiesScriptEngine, collision); - entityScriptB.property("collisionWithEntity").call(entityScriptA, args); - } + QScriptValue entityScriptB = loadEntityScript(idB); + if (entityScriptB.property("collisionWithEntity").isValid()) { + QScriptValueList args; + args << idB.toScriptValue(_entitiesScriptEngine); + args << idA.toScriptValue(_entitiesScriptEngine); + args << collisionToScriptValue(_entitiesScriptEngine, collision); + entityScriptB.property("collisionWithEntity").call(entityScriptA, args); } } From a8d48e592f596ca116daa9ead613838fe65fb727 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 23 Feb 2015 09:44:18 -0800 Subject: [PATCH 08/31] removing debug messages --- .../src/EntityTreeRenderer.cpp | 3 +- libraries/script-engine/src/ScriptEngine.cpp | 39 +++++-------------- libraries/script-engine/src/ScriptEngine.h | 2 +- 3 files changed, 11 insertions(+), 33 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 18813de519..fdaaa6422b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -68,7 +68,6 @@ EntityTreeRenderer::~EntityTreeRenderer() { // this _sandboxScriptEngine implementation is confusing and potentially error prone because it's not a full fledged // ScriptEngine that has been fully connected. We did this so that scripts that were ill-formed could be evaluated // but not execute against the application. - qDebug() << "EntityTreeRenderer::~EntityTreeRenderer() delete _sandboxScriptEngine!!!!!"; delete _sandboxScriptEngine; _sandboxScriptEngine = NULL; } @@ -171,7 +170,7 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) { if (_shuttingDown) { - return QScriptValue(); // no entity... + return QScriptValue(); // since we're shutting down, we don't load any more scripts } if (!entity) { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 9ec76e38b2..6cae9fcfa4 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -94,43 +94,33 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _isUserLoaded(false), _arrayBufferClass(new ArrayBufferClass(this)) { - qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::ScriptEngine() " << getFilename() << "[" << this << "]"; _allKnownScriptEngines.insert(this); } ScriptEngine::~ScriptEngine() { - qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::~ScriptEngine() " << getFilename(); _allKnownScriptEngines.remove(this); } QSet ScriptEngine::_allKnownScriptEngines; -void ScriptEngine::gracefullyStopAllScripts(QObject* application) { - qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- START ------------------"; - - +void ScriptEngine::stopAllScripts(QObject* application) { QMutableSetIterator i(_allKnownScriptEngines); while (i.hasNext()) { ScriptEngine* scriptEngine = i.next(); - qDebug() << (void*)scriptEngine; - - if (scriptEngine->isRunning()) { - qDebug() << "scriptEngine still alive:" << scriptEngine->getFilename() << "[" << scriptEngine << "]"; + // NOTE: typically all script engines are running. But there's at least one known exception to this, the + // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using + // them. We don't need to stop scripts that aren't running. + if (scriptEngine->isRunning()) { QEventLoop loop; QObject::connect(scriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); scriptEngine->disconnect(application); scriptEngine->stop(); - qDebug() << "waiting on script to stop... "; loop.exec(); - qDebug() << "done waiting... "; - } else { - qDebug() << "WARNING! scriptEngine [" << (void*)scriptEngine << "] still in _allKnownScriptEngines but not running??? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"; } } - qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::gracefullyStopAllScripts() ----------- DONE ------------------"; } QString ScriptEngine::getFilename() const { @@ -411,14 +401,12 @@ void ScriptEngine::run() { } if (_isFinished) { - qDebug() << "ScriptEngine::run()... while() about to break " << getFilename(); break; } QCoreApplication::processEvents(); if (_isFinished) { - qDebug() << "ScriptEngine::run()... while() about to break " << getFilename(); break; } @@ -548,7 +536,6 @@ void ScriptEngine::run() { } lastUpdate = now; } - qDebug() << "ScriptEngine::run()... about to emit scriptEnding() " << getFilename(); emit scriptEnding(); // kill the avatar identity timer @@ -566,25 +553,19 @@ void ScriptEngine::run() { // If we were on a thread, then wait till it's done if (thread()) { - qDebug() << "ScriptEngine::run()... about to call thread()->quit() " << getFilename(); thread()->quit(); } - qDebug() << "ScriptEngine::run()... about to emit finished() " << getFilename(); emit finished(_fileNameString); _isRunning = false; - qDebug() << "ScriptEngine::run()... about to emit runningStateChanged() " << getFilename(); emit runningStateChanged(); - qDebug() << "ScriptEngine::run()... about to emit doneRunning() " << getFilename(); emit doneRunning(); - qDebug() << "ScriptEngine::run()... DONE WITH run()... " << getFilename(); } void ScriptEngine::stop() { - qDebug() << "ScriptEngine::stop()... " << getFilename(); _isFinished = true; emit runningStateChanged(); } @@ -666,12 +647,10 @@ void ScriptEngine::print(const QString& message) { emit printedMessage(message); } -/** - * If a callback is specified, the included files will be loaded asynchronously and the callback will be called - * when all of the files have finished loading. - * If no callback is specified, the included files will be loaded synchronously and will block execution until - * all of the files have finished loading. - */ +// If a callback is specified, the included files will be loaded asynchronously and the callback will be called +// when all of the files have finished loading. +// If no callback is specified, the included files will be loaded synchronously and will block execution until +// all of the files have finished loading. void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) { QList urls; for (QString file : includeFiles) { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 1bd07ba220..ab32f2c0a5 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -93,7 +93,7 @@ public: QString getFilename() const; - static void gracefullyStopAllScripts(QObject* application); + static void stopAllScripts(QObject* application); public slots: void loadURL(const QUrl& scriptURL); From 85cec79ff5566125a1721ac61420e7ba142c0a23 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 23 Feb 2015 09:44:22 -0800 Subject: [PATCH 09/31] removing debug messages --- interface/src/Application.cpp | 44 +++-------------------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2fe11608a5..25ee53f187 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -527,21 +527,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : } void Application::aboutToQuit() { -qDebug() << "Application::aboutToQuit()"; _aboutToQuit = true; cleanupBeforeQuit(); } void Application::cleanupBeforeQuit() { - qDebug() << "Application::cleanupBeforeQuit() ------------ START -----------------"; - - // stop entities running scripts - _entities.shutdown(); - - // stop all running scripts - ScriptEngine::gracefullyStopAllScripts(this); - + + _entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts + ScriptEngine::stopAllScripts(this); // stop all currently running global scripts // first stop all timers directly or by invokeMethod // depending on what thread they run in @@ -582,65 +576,36 @@ void Application::cleanupBeforeQuit() { // destroy the AudioClient so it and its thread have a chance to go down safely DependencyManager::destroy(); - - qDebug() << "Application::cleanupBeforeQuit() ------------ DONE -----------------"; } Application::~Application() { - qDebug() << "Application::~Application() ------------ START -----------------"; - - - qDebug() << "Application::~Application() line:" << __LINE__; EntityTree* tree = _entities.getTree(); - qDebug() << "Application::~Application() line:" << __LINE__; tree->lockForWrite(); - qDebug() << "Application::~Application() line:" << __LINE__; _entities.getTree()->setSimulation(NULL); - qDebug() << "Application::~Application() line:" << __LINE__; tree->unlock(); - qDebug() << "Application::~Application() line:" << __LINE__; - qDebug() << "Application::~Application() line:" << __LINE__; qInstallMessageHandler(NULL); - qDebug() << "Application::~Application() line:" << __LINE__; // ask the datagram processing thread to quit and wait until it is done - qDebug() << "Application::~Application() line:" << __LINE__; _nodeThread->quit(); - qDebug() << "Application::~Application() line:" << __LINE__; _nodeThread->wait(); - qDebug() << "Application::~Application() line:" << __LINE__; - qDebug() << "Application::~Application() line:" << __LINE__; _octreeProcessor.terminate(); - qDebug() << "Application::~Application() line:" << __LINE__; _entityEditSender.terminate(); - qDebug() << "Application::~Application() line:" << __LINE__; - qDebug() << "Application::~Application() line:" << __LINE__; Menu::getInstance()->deleteLater(); - qDebug() << "Application::~Application() line:" << __LINE__; - qDebug() << "Application::~Application() line:" << __LINE__; _myAvatar = NULL; - qDebug() << "Application::~Application() line:" << __LINE__; - qDebug() << "Application::~Application() line:" << __LINE__; ModelEntityItem::cleanupLoadedAnimations() ; - qDebug() << "Application::~Application() line:" << __LINE__; - qDebug() << "Application::~Application() line:" << __LINE__; DependencyManager::destroy(); - qDebug() << "Application::~Application() line:" << __LINE__; - qDebug() << "start destroying ResourceCaches Application::~Application() line:" << __LINE__; DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); - qDebug() << "done destroying ResourceCaches Application::~Application() line:" << __LINE__; - qDebug() << "Application::~Application() ------------ DONE -----------------"; } void Application::initializeGL() { @@ -3469,7 +3434,6 @@ void Application::clearScriptsBeforeRunning() { } void Application::saveScripts() { -qDebug() << "Application::saveScripts()"; // Saves all currently running user-loaded scripts Settings settings; settings.beginWriteArray(SETTINGS_KEY); @@ -3638,7 +3602,6 @@ void Application::handleScriptLoadError(const QString& scriptFilename) { } void Application::scriptFinished(const QString& scriptName) { - qDebug() << "Application::scriptFinished(), scriptName:" << scriptName; const QString& scriptURLString = QUrl(scriptName).toString(); QHash::iterator it = _scriptEnginesHash.find(scriptURLString); if (it != _scriptEnginesHash.end()) { @@ -3649,7 +3612,6 @@ void Application::scriptFinished(const QString& scriptName) { } void Application::stopAllScripts(bool restart) { - qDebug() << "Application::stopAllScripts()... restart:" << restart; // stops all current running scripts for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); it != _scriptEnginesHash.constEnd(); it++) { From 1efa7b28b06643da311212dcd059fcddf88bc573 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 23 Feb 2015 10:04:14 -0800 Subject: [PATCH 10/31] removed dead code --- libraries/script-engine/src/ScriptEngine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 6cae9fcfa4..17237d7843 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -531,7 +531,6 @@ void ScriptEngine::run() { } if (!_isFinished) { - //qDebug() << "ScriptEngine::run()... about to emit update() _scriptName:" << _scriptName << "_fileNameString:" << _fileNameString << "_isFinished:" << _isFinished; emit update(deltaTime); } lastUpdate = now; From 7e2d355b56b2cc0cc594151b210e9f4bdfb7d410 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 23 Feb 2015 11:40:30 -0800 Subject: [PATCH 11/31] first cut at properly shutting down timers while shutting down scripts --- libraries/script-engine/src/ScriptEngine.cpp | 14 ++++++++++++++ libraries/script-engine/src/ScriptEngine.h | 1 + 2 files changed, 15 insertions(+) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 17237d7843..0919dc5d59 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -535,6 +535,9 @@ void ScriptEngine::run() { } lastUpdate = now; } + + stopAllTimers(); // make sure all our timers are stopped if the script is ending + emit scriptEnding(); // kill the avatar identity timer @@ -564,6 +567,17 @@ void ScriptEngine::run() { emit doneRunning(); } +// NOTE: This is private because it must be called on the same thread that created the timers, which is why +// we want to only call it in our own run "shutdown" processing. +void ScriptEngine::stopAllTimers() { + QMutableHashIterator i(_timerFunctionMap); + while (i.hasNext()) { + i.next(); + QTimer* timer = i.key(); + stopTimer(timer); + } +} + void ScriptEngine::stop() { _isFinished = true; emit runningStateChanged(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index ab32f2c0a5..8963a1e0f6 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -141,6 +141,7 @@ protected: int _numAvatarSoundSentBytes; private: + void stopAllTimers(); void sendAvatarIdentityPacket(); void sendAvatarBillboardPacket(); From 793116b90cff736102f74f0a90137faaad4fe463 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 23 Feb 2015 21:00:26 +0100 Subject: [PATCH 12/31] ability to mute all notifications or just certain types --- examples/notifications.js | 135 ++++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 33 deletions(-) diff --git a/examples/notifications.js b/examples/notifications.js index f9d2ba83ed..27192ed789 100644 --- a/examples/notifications.js +++ b/examples/notifications.js @@ -38,11 +38,13 @@ // function onIncomingMessage(user, message) { // //do stuff here; // var text = "This is a notification"; -// wordWrap(text); +// var wrappedText = wordWrap(text); +// createNotification(wrappedText, NotificationType.SNAPSHOT); // } // // This new function must call wordWrap(text) if the length of message is longer than 42 chars or unknown. -// wordWrap() will format the text to fit the notifications overlay and send it to createNotification(text). +// wordWrap() will format the text to fit the notifications overlay and return it +// after that we will send it to createNotification(text). // If the message is 42 chars or less you should bypass wordWrap() and call createNotification() directly. @@ -50,12 +52,12 @@ // // 1. Add a key to the keyPressEvent(key). // 2. Declare a text string. -// 3. Call createNotifications(text) parsing the text. +// 3. Call createNotifications(text, NotificationType) parsing the text. // example: // var welcome; // if (key.text == "q") { //queries number of users online // var welcome = "There are " + GlobalServices.onlineUsers.length + " users online now."; -// createNotification(welcome); +// createNotification(welcome, NotificationType.USERS_ONLINE); // } Script.include("./libraries/globals.js"); Script.include("./libraries/soundArray.js"); @@ -83,6 +85,46 @@ var last_users = GlobalServices.onlineUsers; var users = []; var ctrlIsPressed = false; var ready = true; +var MENU_NAME = 'Tools > Notifications'; +var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds"; +var NOTIFICATION_MENU_ITEM_POST = " Notifications"; +var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; +var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; + +var NotificationType = { + UNKNOWN: 0, + USER_JOINS: 1, + USER_LEAVES: 2, + MUTE_TOGGLE: 3, + CHAT_MENTION: 4, + USERS_ONLINE: 5, + SNAPSHOT: 6, + WINDOW_RESIZE: 7, + properties: [ + { text: "User Join" }, + { text: "User Leave" }, + { text: "Mute Toggle" }, + { text: "Chat Mention" }, + { text: "Users Online" }, + { text: "Snapshot" }, + { text: "Window Resize" } + ], + getTypeFromMenuItem: function(menuItemName) { + if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) { + return NotificationType.UNKNOWN; + } + var preMenuItemName = menuItemName.substr(0, menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length); + for (type in this.properties) { + if (this.properties[type].text === preMenuItemName) { + return parseInt(type) + 1; + } + } + return NotificationType.UNKNOWN; + }, + getMenuString: function(type) { + return this.properties[type - 1].text + NOTIFICATION_MENU_ITEM_POST; + } +}; var randomSounds = new SoundArray({ localOnly: true }, true); var numberOfSounds = 2; @@ -90,15 +132,6 @@ for (var i = 1; i <= numberOfSounds; i++) { randomSounds.addSound(HIFI_PUBLIC_BUCKET + "sounds/UI/notification-general" + i + ".raw"); } -// When our script shuts down, we should clean up all of our overlays -function scriptEnding() { - for (i = 0; i < notifications.length; i++) { - Overlays.deleteOverlay(notifications[i]); - Overlays.deleteOverlay(buttons[i]); - } -} -Script.scriptEnding.connect(scriptEnding); - var notifications = []; var buttons = []; var times = []; @@ -211,8 +244,6 @@ function notify(notice, button, height) { positions, last; - randomSounds.playRandom(); - if (isOnHMD) { // Calculate 3D values from 2D overlay properties. @@ -257,7 +288,7 @@ function notify(notice, button, height) { } // This function creates and sizes the overlays -function createNotification(text) { +function createNotification(text, notificationType) { var count = (text.match(/\n/g) || []).length, breakPoint = 43.0, // length when new line is added extraLine = 0, @@ -307,6 +338,12 @@ function createNotification(text) { alpha: backgroundAlpha }; + if (Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) && + Menu.isOptionChecked(NotificationType.getMenuString(notificationType))) + { + randomSounds.playRandom(); + } + notify(noticeProperties, buttonProperties, height); } @@ -345,8 +382,7 @@ function stringDivider(str, slotWidth, spaceReplacer) { // formats string to add newline every 43 chars function wordWrap(str) { - var result = stringDivider(str, 43.0, "\n"); - createNotification(result); + return stringDivider(str, 43.0, "\n"); } // This fires a notification on window resize @@ -358,7 +394,7 @@ function checkSize() { windowDimensions = Controller.getViewportDimensions(); overlayLocationX = (windowDimensions.x - (width + 60.0)); buttonLocationX = overlayLocationX + (width - 35.0); - createNotification(windowResize); + createNotification(windowResize, NotificationType.WINDOW_RESIZE); } } @@ -442,10 +478,7 @@ var STARTUP_TIMEOUT = 500, // ms // This reports the number of users online at startup function reportUsers() { - var welcome; - - welcome = "Welcome! There are " + GlobalServices.onlineUsers.length + " users online now."; - createNotification(welcome); + createNotification("Welcome! There are " + GlobalServices.onlineUsers.length + " users online now.", NotificationType.USERS_ONLINE); } function finishStartup() { @@ -472,13 +505,13 @@ function onOnlineUsersChanged(users) { if (!isStartingUp()) { // Skip user notifications at startup. for (i = 0; i < users.length; i += 1) { if (last_users.indexOf(users[i]) === -1.0) { - createNotification(users[i] + " has joined"); + createNotification(users[i] + " has joined", NotificationType.USER_JOINS); } } for (i = 0; i < last_users.length; i += 1) { if (users.indexOf(last_users[i]) === -1.0) { - createNotification(last_users[i] + " has left"); + createNotification(last_users[i] + " has left", NotificationType.USER_LEAVES); } } } @@ -497,7 +530,7 @@ function onIncomingMessage(user, message) { thisAlert = user + ": " + myMessage; if (myMessage.indexOf(alertMe) > -1.0) { - wordWrap(thisAlert); + CreateNotification(wordWrap(thisAlert), NotificationType.CHAT_MENTION); } } @@ -506,9 +539,9 @@ function onMuteStateChanged() { var muteState, muteString; - muteState = AudioDevice.getMuted() ? "muted" : "unmuted"; + muteState = AudioDevice.getMuted() ? "muted" : "unmuted"; muteString = "Microphone is now " + muteState; - createNotification(muteString); + createNotification(muteString, NotificationType.MUTE_TOGGLE); } // handles mouse clicks on buttons @@ -551,25 +584,58 @@ function keyPressEvent(key) { if (key.text === "q") { //queries number of users online numUsers = GlobalServices.onlineUsers.length; welcome = "There are " + numUsers + " users online now."; - createNotification(welcome); + createNotification(welcome, NotificationType.USERS_ONLINE); } if (key.text === "s") { if (ctrlIsPressed === true) { noteString = "Snapshot taken."; - createNotification(noteString); + createNotification(noteString, NotificationType.SNAPSHOT); } } } +function setup() { + Menu.addMenu(MENU_NAME); + var checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING); + checked = checked === '' ? true : checked; + Menu.addMenuItem({ + menuName: MENU_NAME, + menuItemName: PLAY_NOTIFICATION_SOUNDS_MENU_ITEM, + isCheckable: true, + isChecked: Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING) + }); + Menu.addSeparator(MENU_NAME, "Play sounds for:"); + for (type in NotificationType.properties) { + checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + (parseInt(type) + 1)); + checked = checked === '' ? true : checked; + Menu.addMenuItem({ + menuName: MENU_NAME, + menuItemName: NotificationType.properties[type].text + NOTIFICATION_MENU_ITEM_POST, + isCheckable: true, + isChecked: checked + }); + } +} + // When our script shuts down, we should clean up all of our overlays function scriptEnding() { - var i; - - for (i = 0; i < notifications.length; i += 1) { + for (var i = 0; i < notifications.length; i++) { Overlays.deleteOverlay(notifications[i]); Overlays.deleteOverlay(buttons[i]); } + Menu.removeMenu(MENU_NAME); +} + +function menuItemEvent(menuItem) { + if (menuItem === PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) { + Settings.setValue(PLAY_NOTIFICATION_SOUNDS_SETTING, Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM)); + return; + } + var notificationType = NotificationType.getTypeFromMenuItem(menuItem); + if (notificationType !== notificationType.UNKNOWN) { + Settings.setValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + notificationType, Menu.isOptionChecked(menuItem)); + } } AudioDevice.muteToggled.connect(onMuteStateChanged); @@ -580,3 +646,6 @@ GlobalServices.incomingMessage.connect(onIncomingMessage); Controller.keyReleaseEvent.connect(keyReleaseEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); +Menu.menuItemEvent.connect(menuItemEvent); + +setup(); From 6be8f4c0ec8dcffe07e99f22ecec501e1f07d7a0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 23 Feb 2015 17:32:31 -0800 Subject: [PATCH 13/31] more work on improving shutdown behavior --- interface/src/Application.cpp | 11 ++- .../src/EntityTreeRenderer.cpp | 2 + libraries/script-engine/src/ScriptEngine.cpp | 81 ++++++++++++++++--- libraries/script-engine/src/ScriptEngine.h | 4 + 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 25ee53f187..32854a1781 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3538,7 +3538,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); // when the application is about to quit, stop our script engine so it unwinds properly - connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop())); + //connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop())); auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::nodeKilled, scriptEngine, &ScriptEngine::nodeKilled); @@ -3550,7 +3550,14 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri } ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded, - bool loadScriptFromEditor, bool activateMainWindow) { + bool loadScriptFromEditor, bool activateMainWindow) { + + qDebug() << "Application::loadScript() " << scriptFilename << "line:" << __LINE__; + if (isAboutToQuit()) { + qDebug() << "Application::loadScript() WHILE QUITTING.... what to do????" << scriptFilename << "line:" << __LINE__; + return NULL; + } + QUrl scriptUrl(scriptFilename); const QString& scriptURLString = scriptUrl.toString(); if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index fdaaa6422b..9deafe17da 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -59,6 +59,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf } EntityTreeRenderer::~EntityTreeRenderer() { + qDebug() << "EntityTreeRenderer::~EntityTreeRenderer() -------- BEGIN -----------"; // NOTE: we don't need to delete _entitiesScriptEngine because it's owned by the application and gets cleaned up // automatically but we do need to delete our sandbox script engine. @@ -71,6 +72,7 @@ EntityTreeRenderer::~EntityTreeRenderer() { delete _sandboxScriptEngine; _sandboxScriptEngine = NULL; } + qDebug() << "EntityTreeRenderer::~EntityTreeRenderer() -------- DONE -----------"; } void EntityTreeRenderer::clear() { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 0919dc5d59..fe568ab077 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -94,33 +94,78 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _isUserLoaded(false), _arrayBufferClass(new ArrayBufferClass(this)) { + qDebug() << "ScriptEngine::ScriptEngine() " << getFilename() << "[" << ((void*)this) << "]" << " -------- BEGIN -----------"; + _allScriptsMutex.lock(); _allKnownScriptEngines.insert(this); + _allScriptsMutex.unlock(); + qDebug() << "ScriptEngine::ScriptEngine() " << getFilename() << " -------- DONE -----------"; } ScriptEngine::~ScriptEngine() { - _allKnownScriptEngines.remove(this); + qDebug() << "ScriptEngine::~ScriptEngine() " << getFilename() << "[" << ((void*)this) << "]" << " -------- BEGIN -----------"; + if (!_stoppingAllScripts) { + _allScriptsMutex.lock(); + qDebug() << "ScriptEngine::~ScriptEngine() " << getFilename() << " removing from list of scripts"; + _allKnownScriptEngines.remove(this); + _allScriptsMutex.unlock(); + } else { + qDebug() << "ScriptEngine::~ScriptEngine() " << getFilename() << " NOT removing from list of scripts here..."; + } + qDebug() << "ScriptEngine::~ScriptEngine() " << getFilename() << " -------- DONE -----------"; } QSet ScriptEngine::_allKnownScriptEngines; +QMutex ScriptEngine::_allScriptsMutex; +bool ScriptEngine::_stoppingAllScripts = false; void ScriptEngine::stopAllScripts(QObject* application) { + + qDebug() << "ScriptEngine::stopAllScripts() -------- BEGIN -----------"; + _allScriptsMutex.lock(); + _stoppingAllScripts = true; + QMutableSetIterator i(_allKnownScriptEngines); while (i.hasNext()) { ScriptEngine* scriptEngine = i.next(); + qDebug() << "ScriptEngine::stopAllScripts() scriptEngine: " << (void*)scriptEngine; + + QString scriptName = scriptEngine->getFilename(); + + qDebug() << "ScriptEngine::stopAllScripts() considering script: " << scriptName << "evaluatePending:" << scriptEngine->evaluatePending(); + // NOTE: typically all script engines are running. But there's at least one known exception to this, the // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using // them. We don't need to stop scripts that aren't running. if (scriptEngine->isRunning()) { + if (scriptEngine->evaluatePending()) { + qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__ << "waiting for evaluation to complete...."; + QEventLoop loop; + QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); + loop.exec(); + qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__ << "evaluation complete...."; + } + + qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; + QEventLoop loop; QObject::connect(scriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); - - scriptEngine->disconnect(application); - scriptEngine->stop(); + qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; + scriptEngine->disconnect(application); + qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; + scriptEngine->stop(); + qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; loop.exec(); + qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; + i.remove(); + } else { + qDebug() << "ScriptEngine::stopAllScripts() script: " << scriptName << " was not running... skipping it's stop() call."; } } + _stoppingAllScripts = false; + _allScriptsMutex.unlock(); + qDebug() << "ScriptEngine::stopAllScripts() -------- DONE -----------"; } QString ScriptEngine::getFilename() const { @@ -347,6 +392,8 @@ void ScriptEngine::evaluate() { } QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { + qDebug() << "ScriptEngine::evaluate() " << getFilename() << " line:" << __LINE__; + _evaluatePending = true; QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); @@ -354,6 +401,8 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN } emit evaluationFinished(result, hasUncaughtException()); clearExceptions(); + _evaluatePending = false; + qDebug() << "ScriptEngine::evaluate() " << getFilename() << " line:" << __LINE__; return result; } @@ -370,30 +419,36 @@ void ScriptEngine::sendAvatarBillboardPacket() { } void ScriptEngine::run() { + qDebug() << "ScriptEngine::run() " << getFilename() << " -------- BEGIN -----------"; + if (!_isInitialized) { + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; init(); + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; } + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; _isRunning = true; _isFinished = false; + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; emit runningStateChanged(); + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; QScriptValue result = evaluate(_scriptContents); - if (hasUncaughtException()) { - int line = uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); - emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); - clearExceptions(); - } + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; QElapsedTimer startTime; startTime.start(); int thisFrame = 0; + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; auto nodeList = DependencyManager::get(); qint64 lastUpdate = usecTimestampNow(); + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; while (!_isFinished) { int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec if (usecToSleep > 0) { @@ -535,6 +590,7 @@ void ScriptEngine::run() { } lastUpdate = now; } + qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; stopAllTimers(); // make sure all our timers are stopped if the script is ending @@ -565,6 +621,7 @@ void ScriptEngine::run() { emit runningStateChanged(); emit doneRunning(); + qDebug() << "ScriptEngine::run() " << getFilename() << " -------- DONE -----------" << " line:" << __LINE__; } // NOTE: This is private because it must be called on the same thread that created the timers, which is why @@ -579,6 +636,7 @@ void ScriptEngine::stopAllTimers() { } void ScriptEngine::stop() { + qDebug() << "ScriptEngine::stop() " << getFilename() << "[" << ((void*)this) << "]"; _isFinished = true; emit runningStateChanged(); } @@ -710,8 +768,11 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { } void ScriptEngine::load(const QString& loadFile) { + qDebug() << "ScriptEngine::load() " << getFilename() << "[" << ((void*)this) << "]" << "line:" << __LINE__; QUrl url = resolvePath(loadFile); + qDebug() << "ScriptEngine::load() " << getFilename() << "[" << ((void*)this) << "]" << "line:" << __LINE__; emit loadScript(url.toString(), false); + qDebug() << "ScriptEngine::load() " << getFilename() << "[" << ((void*)this) << "]" << "line:" << __LINE__; } void ScriptEngine::nodeKilled(SharedNodePointer node) { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8963a1e0f6..a672646c79 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -85,6 +85,7 @@ public: bool isFinished() const { return _isFinished; } bool isRunning() const { return _isRunning; } + bool evaluatePending() const { return _evaluatePending; } void setUserLoaded(bool isUserLoaded) { _isUserLoaded = isUserLoaded; } bool isUserLoaded() const { return _isUserLoaded; } @@ -131,6 +132,7 @@ protected: QString _parentURL; bool _isFinished; bool _isRunning; + bool _evaluatePending = false; bool _isInitialized; bool _isAvatar; QTimer* _avatarIdentityTimer; @@ -167,6 +169,8 @@ private slots: private: static QSet _allKnownScriptEngines; + static QMutex _allScriptsMutex; + static bool _stoppingAllScripts; }; #endif // hifi_ScriptEngine_h From ab590440be3f3fa70e99a762579b2d43cc6da19e Mon Sep 17 00:00:00 2001 From: Seefo Date: Mon, 23 Feb 2015 22:15:24 -0500 Subject: [PATCH 14/31] Cleaned up warnings on Windows --- libraries/metavoxels/src/Spanner.cpp | 12 ++++++------ tests/jitter/src/main.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index fbd0d311f5..fd5a59fdfb 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -1959,7 +1959,7 @@ HeightfieldNode* HeightfieldNode::fillHeight(const glm::vec3& translation, const } else { colorWidth = innerHeightWidth + HeightfieldData::SHARED_EDGE; colorHeight = innerHeightHeight + HeightfieldData::SHARED_EDGE; - newColorContents = QByteArray(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFF); + newColorContents = QByteArray(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFFu); } int innerColorWidth = colorWidth - HeightfieldData::SHARED_EDGE; int innerColorHeight = colorHeight - HeightfieldData::SHARED_EDGE; @@ -2185,7 +2185,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons } else { colorWidth = innerHeightWidth + HeightfieldData::SHARED_EDGE; colorHeight = innerHeightHeight + HeightfieldData::SHARED_EDGE; - newColorContents = QByteArray(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFF); + newColorContents = QByteArray(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFFu); } int innerColorWidth = colorWidth - HeightfieldData::SHARED_EDGE; int innerColorHeight = colorHeight - HeightfieldData::SHARED_EDGE; @@ -2428,7 +2428,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons } } } - bool nextAlphaY = stackDest->getEntryAlpha(y + 1, voxelHeight); + int nextAlphaY = stackDest->getEntryAlpha(y + 1, voxelHeight); if (nextAlphaY == currentAlpha) { entryDest->hermiteY = 0; @@ -2447,7 +2447,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons } int nextStackZ = (int)stackZ + 1; if (nextStackZ <= innerStackHeight) { - bool nextAlphaZ = newStackContents.at(nextStackZ * stackWidth + (int)stackX).getEntryAlpha( + int nextAlphaZ = newStackContents.at(nextStackZ * stackWidth + (int)stackX).getEntryAlpha( y, nextVoxelHeightZ); if (nextAlphaZ == currentAlpha) { entryDest->hermiteZ = 0; @@ -2828,7 +2828,7 @@ void HeightfieldNode::mergeChildren(bool height, bool colorMaterial) { _height.reset(); } if (colorWidth > 0 && colorMaterial) { - QByteArray colorContents(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFF); + QByteArray colorContents(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFFu); for (int i = 0; i < CHILD_COUNT; i++) { HeightfieldColorPointer childColor = _children[i]->getColor(); if (!childColor) { @@ -3266,7 +3266,7 @@ HeightfieldNode* HeightfieldNode::subdivide(const QVector& heightConten } for (int i = 0; i < CHILD_COUNT; i++) { QVector childHeightContents(heightWidth * heightHeight); - QByteArray childColorContents(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFF); + QByteArray childColorContents(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFFu); QByteArray childMaterialContents(materialWidth * materialHeight, 0); QVector childStackContents(stackWidth * stackHeight); diff --git a/tests/jitter/src/main.cpp b/tests/jitter/src/main.cpp index baaa2d08d6..788ae89c6f 100644 --- a/tests/jitter/src/main.cpp +++ b/tests/jitter/src/main.cpp @@ -8,7 +8,7 @@ #include #ifdef _WINDOWS -#include +#include #else #include #include @@ -76,7 +76,7 @@ void runSend(const char* addressOption, int port, int gap, int size, int report) memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = inet_addr(addressOption); + inet_pton(AF_INET, addressOption, &servaddr.sin_addr); servaddr.sin_port = htons(port); const int SAMPLES_FOR_SECOND = 1000000 / gap; From 4641bd0cd99176192ec03e5a7a3facb8a41cdd24 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Feb 2015 10:47:37 -0800 Subject: [PATCH 15/31] Add Window.domainChanged signal for scripting --- interface/src/scripting/WindowScriptingInterface.cpp | 3 +++ interface/src/scripting/WindowScriptingInterface.h | 1 + 2 files changed, 4 insertions(+) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index c4b288347d..fc3eefe260 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -18,6 +18,7 @@ #include #include "Application.h" +#include "DomainHandler.h" #include "MainWindow.h" #include "Menu.h" #include "ui/ModelsBrowser.h" @@ -34,6 +35,8 @@ WindowScriptingInterface::WindowScriptingInterface() : _nonBlockingFormActive(false), _formResult(QDialog::Rejected) { + const DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); + connect(&domainHandler, &DomainHandler::hostnameChanged, this, &WindowScriptingInterface::domainChanged); } WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height) { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 66d0ab9306..5c0aa4f0a8 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -57,6 +57,7 @@ public slots: QScriptValue peekNonBlockingFormResult(QScriptValue array); signals: + void domainChanged(const QString& domainHostname); void inlineButtonClicked(const QString& name); void nonBlockingFormClosed(); From c9818c184a41fb9835e28d58d141c85c8e03b0d5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Feb 2015 10:47:55 -0800 Subject: [PATCH 16/31] Update editEntities to turn off when switching domains --- examples/editEntities.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/editEntities.js b/examples/editEntities.js index 61100b4556..9b13b167e7 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -396,6 +396,10 @@ var toolBar = (function () { return handled; } + Window.domainChanged.connect(function() { + that.setActive(false); + }); + that.cleanup = function () { toolBar.cleanup(); }; From fd93b99f03fc3e8a8ccb0b19b93377ab8c98122e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Feb 2015 14:02:46 -0800 Subject: [PATCH 17/31] more hacking on script shutdown behavior --- interface/src/Application.cpp | 12 +- .../src/EntityTreeRenderer.cpp | 3 - libraries/script-engine/src/ScriptEngine.cpp | 264 ++++++++++++++---- libraries/script-engine/src/ScriptEngine.h | 9 +- 4 files changed, 231 insertions(+), 57 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 32854a1781..7184021239 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3552,9 +3552,11 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, bool activateMainWindow) { - qDebug() << "Application::loadScript() " << scriptFilename << "line:" << __LINE__; + qDebug() << "Application::loadScript() ---- BEGIN ---- Script:" << scriptFilename; + if (isAboutToQuit()) { - qDebug() << "Application::loadScript() WHILE QUITTING.... what to do????" << scriptFilename << "line:" << __LINE__; + qDebug() << "Requests to load scripts while quitting are ignored. Script:" << scriptFilename; + qDebug() << "Application::loadScript() ---- END ---- Script:" << scriptFilename; return NULL; } @@ -3563,6 +3565,8 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor && !_scriptEnginesHash[scriptURLString]->isFinished()) { + qDebug() << "Application::loadScript() from _scriptEnginesHash[scriptURLString].... Script:" << scriptFilename; + qDebug() << "Application::loadScript() ---- END ---- Script:" << scriptFilename; return _scriptEnginesHash[scriptURLString]; } @@ -3581,6 +3585,7 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &Application::handleScriptLoadError); // get the script engine object to load the script at the designated script URL + qDebug() << "Application::loadScript() about to call loadURL() scriptUrl:" << scriptUrl; scriptEngine->loadURL(scriptUrl); } @@ -3589,6 +3594,9 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser _window->activateWindow(); } + qDebug() << "Application::loadScript() newly created scriptEngine.... Script:" << scriptFilename; + qDebug() << "Application::loadScript() ---- END ---- Script:" << scriptFilename; + return scriptEngine; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 9deafe17da..8648cea285 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -59,10 +59,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf } EntityTreeRenderer::~EntityTreeRenderer() { - qDebug() << "EntityTreeRenderer::~EntityTreeRenderer() -------- BEGIN -----------"; // NOTE: we don't need to delete _entitiesScriptEngine because it's owned by the application and gets cleaned up // automatically but we do need to delete our sandbox script engine. - if (_sandboxScriptEngine) { // NOTE: is it possible this is a problem? I think that we hook the script engine object up to a deleteLater() // call inside of registerScriptEngineWithApplicationServices() but do we not call that for _sandboxScriptEngine??? @@ -72,7 +70,6 @@ EntityTreeRenderer::~EntityTreeRenderer() { delete _sandboxScriptEngine; _sandboxScriptEngine = NULL; } - qDebug() << "EntityTreeRenderer::~EntityTreeRenderer() -------- DONE -----------"; } void EntityTreeRenderer::clear() { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index fe568ab077..e99cbea0e5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -94,33 +94,32 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _isUserLoaded(false), _arrayBufferClass(new ArrayBufferClass(this)) { - qDebug() << "ScriptEngine::ScriptEngine() " << getFilename() << "[" << ((void*)this) << "]" << " -------- BEGIN -----------"; _allScriptsMutex.lock(); _allKnownScriptEngines.insert(this); _allScriptsMutex.unlock(); - qDebug() << "ScriptEngine::ScriptEngine() " << getFilename() << " -------- DONE -----------"; } ScriptEngine::~ScriptEngine() { - qDebug() << "ScriptEngine::~ScriptEngine() " << getFilename() << "[" << ((void*)this) << "]" << " -------- BEGIN -----------"; + qDebug() << "ScriptEngine::~ScriptEngine() ------- BEGIN ------- script:" << getFilename(); + // If we're not already in the middle of stopping all scripts, then we should remove ourselves + // from the list of running scripts. We don't do this if we're in the process of stopping all scripts + // because that method removes scripts from its list as it iterates them if (!_stoppingAllScripts) { _allScriptsMutex.lock(); - qDebug() << "ScriptEngine::~ScriptEngine() " << getFilename() << " removing from list of scripts"; _allKnownScriptEngines.remove(this); _allScriptsMutex.unlock(); - } else { - qDebug() << "ScriptEngine::~ScriptEngine() " << getFilename() << " NOT removing from list of scripts here..."; } - qDebug() << "ScriptEngine::~ScriptEngine() " << getFilename() << " -------- DONE -----------"; + qDebug() << "ScriptEngine::~ScriptEngine() ------- END ------- script:" << getFilename(); } QSet ScriptEngine::_allKnownScriptEngines; QMutex ScriptEngine::_allScriptsMutex; bool ScriptEngine::_stoppingAllScripts = false; +bool ScriptEngine::_doneRunningThisScript = false; void ScriptEngine::stopAllScripts(QObject* application) { + qDebug() << "ScriptEngine::stopAllScripts() ------- BEGIN -------"; - qDebug() << "ScriptEngine::stopAllScripts() -------- BEGIN -----------"; _allScriptsMutex.lock(); _stoppingAllScripts = true; @@ -128,44 +127,92 @@ void ScriptEngine::stopAllScripts(QObject* application) { while (i.hasNext()) { ScriptEngine* scriptEngine = i.next(); - qDebug() << "ScriptEngine::stopAllScripts() scriptEngine: " << (void*)scriptEngine; - QString scriptName = scriptEngine->getFilename(); - qDebug() << "ScriptEngine::stopAllScripts() considering script: " << scriptName << "evaluatePending:" << scriptEngine->evaluatePending(); + qDebug() << "ScriptEngine::stopAllScripts() considering:" << scriptName + << "isRunning():" << scriptEngine->isRunning() + << "evaluatePending():" << scriptEngine->evaluatePending(); // NOTE: typically all script engines are running. But there's at least one known exception to this, the // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using // them. We don't need to stop scripts that aren't running. if (scriptEngine->isRunning()) { + + // If the script is running, but still evaluating then we need to wait for its evaluation step to + // complete. After that we can handle the stop process appropriately if (scriptEngine->evaluatePending()) { - qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__ << "waiting for evaluation to complete...."; - QEventLoop loop; - QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); - loop.exec(); - qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__ << "evaluation complete...."; + while (scriptEngine->evaluatePending()) { + QEventLoop loop; + QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); + qDebug() << "ScriptEngine::stopAllScripts() while(evaluatePending()) STARTING loop.exec() script:" << scriptName; + loop.exec(); + qDebug() << "ScriptEngine::stopAllScripts() while(evaluatePending()) AFTER loop.exec() script:" << scriptName; + } } - qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; - - QEventLoop loop; - QObject::connect(scriptEngine, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); - - qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; scriptEngine->disconnect(application); - qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; scriptEngine->stop(); - qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; - loop.exec(); - qDebug() << "ScriptEngine::stopAllScripts() handling script: " << scriptName << "line:" << __LINE__; + + qDebug() << "ScriptEngine::stopAllScripts() -- WAITING for waitTillDoneRunning() script:" << scriptName; + scriptEngine->waitTillDoneRunning(); + qDebug() << "ScriptEngine::stopAllScripts() -- AFTER waitTillDoneRunning() script:" << scriptName; i.remove(); } else { - qDebug() << "ScriptEngine::stopAllScripts() script: " << scriptName << " was not running... skipping it's stop() call."; } } _stoppingAllScripts = false; _allScriptsMutex.unlock(); - qDebug() << "ScriptEngine::stopAllScripts() -------- DONE -----------"; + qDebug() << "ScriptEngine::stopAllScripts() ------- DONE -------"; +} + + +void ScriptEngine::waitTillDoneRunning() { + QString scriptName = getFilename(); + qDebug() << "ScriptEngine::waitTillDoneRunning() ------- BEGIN ------- script:" << scriptName; + qDebug() << " _isFinished:" << _isFinished; + qDebug() << " _isRunning:" << _isRunning; + qDebug() << " _isInitialized:" << _isInitialized; + qDebug() << " _evaluatesPending:" << _evaluatesPending; + + if (_isRunning) { + qDebug() << "ScriptEngine::waitTillDoneRunning() SETTING _doneRunningThisScript = false ################################### line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + _doneRunningThisScript = false; + _isWaitingForDoneRunning = true; + + // What can we do here??? + // we will be calling this on the main Application thread, inside of stopAllScripts() + // we want the application thread to continue to process events, because the script will + // likely need to marshall messages across to the main thread. + while (!_doneRunningThisScript && _isRunning) { + + // and run a QEventLoop??? + QEventLoop loop; + QObject::connect(this, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); + qDebug() << "ScriptEngine::waitTillDoneRunning() STARTING loop.exec() script:" << scriptName; + qDebug() << " _doneRunningThisScript:" << _doneRunningThisScript; + qDebug() << " _isRunning:" << _isRunning; + qDebug() << " _isWaitingForDoneRunning:" << _isWaitingForDoneRunning; + qDebug() << " _isFinished:" << _isFinished; + qDebug() << " _isInitialized:" << _isInitialized; + qDebug() << " _evaluatesPending:" << _evaluatesPending; + loop.exec(); + qDebug() << "ScriptEngine::waitTillDoneRunning() AFTER loop.exec() script:" << scriptName; + + // process events + qDebug() << "ScriptEngine::waitTillDoneRunning() STARTING QCoreApplication::processEvents() script:" << scriptName; + QCoreApplication::processEvents(); + qDebug() << "ScriptEngine::waitTillDoneRunning() AFTER QCoreApplication::processEvents() script:" << scriptName; + + if (_doneRunningThisScript) { + qDebug() << "ScriptEngine::waitTillDoneRunning() _doneRunningThisScript after processEvents... breaking!!! script:" << scriptName; + break; + } + } + + _isWaitingForDoneRunning = false; + } + + qDebug() << "ScriptEngine::waitTillDoneRunning() ------- DONE ------- script:" << scriptName; } QString ScriptEngine::getFilename() const { @@ -377,12 +424,23 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func } void ScriptEngine::evaluate() { + if (_stoppingAllScripts) { + qDebug() << "ScriptEngine::evaluate() while shutting down is ignored..."; + qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + return; // bail early + } + + qDebug() << "ScriptEngine::evaluate() -- BEGIN script:" << getFilename() << "[" << this << "]"; if (!_isInitialized) { init(); } + qDebug() << "ScriptEngine::evaluate() -- about to call own evaluate(program) script:" << getFilename() << "[" << this << "]"; QScriptValue result = evaluate(_scriptContents); + qDebug() << "ScriptEngine::evaluate() -- AFTER own evaluate(program) script:" << getFilename() << "[" << this << "]"; + // TODO: why do we check this twice? It seems like the call to clearExcpetions() in the lower level evaluate call + // will cause this code to never actually run... if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); @@ -392,17 +450,30 @@ void ScriptEngine::evaluate() { } QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { - qDebug() << "ScriptEngine::evaluate() " << getFilename() << " line:" << __LINE__; - _evaluatePending = true; + if (_stoppingAllScripts) { + qDebug() << "ScriptEngine::evaluate(program) while shutting down is ignored..."; + qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + return QScriptValue(); // bail early + } + + qDebug() << "ScriptEngine::evaluate(program) -- BEGIN script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + _evaluatesPending++; + qDebug() << "ScriptEngine::evaluate(program) -- after _evaluatesPending++ script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + qDebug() << "ScriptEngine::evaluate(program) -- BEFORE QScriptEngine::evaluate() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); + qDebug() << "ScriptEngine::evaluate(program) -- AFTER QScriptEngine::evaluate() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString(); } + _evaluatesPending--; + qDebug() << "ScriptEngine::evaluate(program) -- after _evaluatesPending-- script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + + qDebug() << "ScriptEngine::evaluate(program) -- ABOUT TO emit evaluationFinished() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; emit evaluationFinished(result, hasUncaughtException()); + qDebug() << "ScriptEngine::evaluate(program) -- AFTER emit evaluationFinished() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; clearExceptions(); - _evaluatePending = false; - qDebug() << "ScriptEngine::evaluate() " << getFilename() << " line:" << __LINE__; + qDebug() << "ScriptEngine::evaluate(program) -- DONE script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; return result; } @@ -419,49 +490,60 @@ void ScriptEngine::sendAvatarBillboardPacket() { } void ScriptEngine::run() { - qDebug() << "ScriptEngine::run() " << getFilename() << " -------- BEGIN -----------"; + // TODO: can we add a short circuit for _stoppingAllScripts here? What does it mean to not start running if + // we're in the process of stopping? + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; if (!_isInitialized) { - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; init(); - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; } - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; _isRunning = true; _isFinished = false; - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; emit runningStateChanged(); - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; QScriptValue result = evaluate(_scriptContents); - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; QElapsedTimer startTime; startTime.start(); int thisFrame = 0; - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; auto nodeList = DependencyManager::get(); qint64 lastUpdate = usecTimestampNow(); - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + while (!_isFinished) { + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec if (usecToSleep > 0) { usleep(usecToSleep); } if (_isFinished) { + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; break; } + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + QCoreApplication::processEvents(); + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + if (_isFinished) { + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; break; } @@ -589,16 +671,38 @@ void ScriptEngine::run() { emit update(deltaTime); } lastUpdate = now; + + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + } - qDebug() << "ScriptEngine::run() " << getFilename() << " line:" << __LINE__; + + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; stopAllTimers(); // make sure all our timers are stopped if the script is ending + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename(); + + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } emit scriptEnding(); + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; // kill the avatar identity timer delete _avatarIdentityTimer; + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) { // release the queue of edit entity messages. _entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages(); @@ -609,19 +713,44 @@ void ScriptEngine::run() { } } + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + // If we were on a thread, then wait till it's done if (thread()) { + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; thread()->quit(); + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + + qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; } emit finished(_fileNameString); - _isRunning = false; + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + _isRunning = false; emit runningStateChanged(); + qDebug() << "ABOUT TO emit doneRunning() script:" << getFilename() << "[" << this << "]"; emit doneRunning(); - qDebug() << "ScriptEngine::run() " << getFilename() << " -------- DONE -----------" << " line:" << __LINE__; + qDebug() << "AFTER emit doneRunning() script:" << getFilename() << "[" << this << "]"; + + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } + + qDebug() << "ScriptEngine::run() SETTING _doneRunningThisScript = true ################################### line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + _doneRunningThisScript = true; + + if (_isWaitingForDoneRunning) { + qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + } } // NOTE: This is private because it must be called on the same thread that created the timers, which is why @@ -636,9 +765,10 @@ void ScriptEngine::stopAllTimers() { } void ScriptEngine::stop() { - qDebug() << "ScriptEngine::stop() " << getFilename() << "[" << ((void*)this) << "]"; + qDebug() << "ScriptEngine::stop() -- START -- line:" << __LINE__ << " script:" << getFilename(); _isFinished = true; emit runningStateChanged(); + qDebug() << "ScriptEngine::stop() -- DONE -- line:" << __LINE__ << " script:" << getFilename(); } void ScriptEngine::timerFired() { @@ -674,10 +804,22 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int } QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) { + if (_stoppingAllScripts) { + qDebug() << "Script.setInterval() while shutting down is ignored..."; + qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + return NULL; // bail early + } + return setupTimerWithInterval(function, intervalMS, false); } QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { + if (_stoppingAllScripts) { + qDebug() << "Script.setTimeout() while shutting down is ignored..."; + qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + return NULL; // bail early + } + return setupTimerWithInterval(function, timeoutMS, true); } @@ -723,6 +865,12 @@ void ScriptEngine::print(const QString& message) { // If no callback is specified, the included files will be loaded synchronously and will block execution until // all of the files have finished loading. void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) { + if (_stoppingAllScripts) { + qDebug() << "Script.include() while shutting down is ignored..."; + qDebug() << " includeFiles:" << includeFiles; + qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + return; // bail early + } QList urls; for (QString file : includeFiles) { urls.append(resolvePath(file)); @@ -736,7 +884,9 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac if (contents.isNull()) { qDebug() << "Error loading file: " << url; } else { + qDebug() << "ScriptEngine::include() BEFORE evaluate() line:" << __LINE__ << " parent script:" << getFilename() << "[" << this << "]" << " url:" << url << "_evaluatesPending:" << _evaluatesPending; QScriptValue result = evaluate(contents, url.toString()); + qDebug() << "ScriptEngine::include() AFTER evaluate() line:" << __LINE__ << " parent script:" << getFilename() << "[" << this << "]" << " url:" << url << "_evaluatesPending:" << _evaluatesPending; } } @@ -762,17 +912,31 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac } void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { + if (_stoppingAllScripts) { + qDebug() << "Script.include() while shutting down is ignored..."; + qDebug() << " includeFile:" << includeFile; + qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + return; // bail early + } + QStringList urls; urls.append(includeFile); include(urls, callback); } +// NOTE: The load() command is similar to the include() command except that it loads the script +// as a stand-alone script. To accomplish this, the ScriptEngine class just emits a signal which +// the Application or other context will connect to in order to know to actually load the script void ScriptEngine::load(const QString& loadFile) { - qDebug() << "ScriptEngine::load() " << getFilename() << "[" << ((void*)this) << "]" << "line:" << __LINE__; + if (_stoppingAllScripts) { + qDebug() << "Script.load() while shutting down is ignored..."; + qDebug() << " loadFile:" << loadFile; + qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + return; // bail early + } + QUrl url = resolvePath(loadFile); - qDebug() << "ScriptEngine::load() " << getFilename() << "[" << ((void*)this) << "]" << "line:" << __LINE__; emit loadScript(url.toString(), false); - qDebug() << "ScriptEngine::load() " << getFilename() << "[" << ((void*)this) << "]" << "line:" << __LINE__; } void ScriptEngine::nodeKilled(SharedNodePointer node) { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index a672646c79..51cacd5e58 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -85,7 +86,7 @@ public: bool isFinished() const { return _isFinished; } bool isRunning() const { return _isRunning; } - bool evaluatePending() const { return _evaluatePending; } + bool evaluatePending() const { return _evaluatesPending > 0; } void setUserLoaded(bool isUserLoaded) { _isUserLoaded = isUserLoaded; } bool isUserLoaded() const { return _isUserLoaded; } @@ -95,6 +96,8 @@ public: QString getFilename() const; static void stopAllScripts(QObject* application); + + void waitTillDoneRunning(); public slots: void loadURL(const QUrl& scriptURL); @@ -132,7 +135,8 @@ protected: QString _parentURL; bool _isFinished; bool _isRunning; - bool _evaluatePending = false; + int _evaluatesPending = 0; + bool _isWaitingForDoneRunning = false; bool _isInitialized; bool _isAvatar; QTimer* _avatarIdentityTimer; @@ -171,6 +175,7 @@ private: static QSet _allKnownScriptEngines; static QMutex _allScriptsMutex; static bool _stoppingAllScripts; + static bool _doneRunningThisScript; }; #endif // hifi_ScriptEngine_h From 89c10ca2ece60d44f330a4b4d410f8f92a7eafef Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Feb 2015 14:36:24 -0800 Subject: [PATCH 18/31] Fix BillboardOverlay::findRayIntersection --- .../src/ui/overlays/BillboardOverlay.cpp | 50 ++++++++++++++++--- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index 27bd0c9102..4ea0e55710 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -12,6 +12,7 @@ #include "Application.h" #include "BillboardOverlay.h" +#include BillboardOverlay::BillboardOverlay() : _fromImage(), @@ -191,18 +192,51 @@ bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::v float& distance, BoxFace& face) { if (_texture) { + // This is taken from Planar3DOverlay. Although it probably makes more sense for this + // overlay type to extend from Planar3DOverlay, the interfaces are different enough (scale vs. dimensions) + // that it would break existing scripts and would require other changes to make up for unique + // features like `isFacingAvatar`. + + RayIntersectionInfo rayInfo; + rayInfo._rayStart = origin; + rayInfo._rayDirection = direction; + rayInfo._rayLength = std::numeric_limits::max(); + bool isNull = _fromImage.isNull(); float width = isNull ? _texture->getWidth() : _fromImage.width(); float height = isNull ? _texture->getHeight() : _fromImage.height(); - float maxSize = glm::max(width, height); - float x = width / (2.0f * maxSize); - float y = -height / (2.0f * maxSize); - float maxDimension = glm::max(x,y); - float scaledDimension = maxDimension * _scale; - glm::vec3 corner = getCenter() - glm::vec3(scaledDimension, scaledDimension, scaledDimension) ; - AACube myCube(corner, scaledDimension * 2.0f); - return myCube.findRayIntersection(origin, direction, distance, face); + PlaneShape plane; + + const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f); + glm::quat rotation; + if (_isFacingAvatar) { + // rotate about vertical to face the camera + rotation = Application::getInstance()->getCamera()->getRotation(); + rotation *= glm::angleAxis(glm::pi(), glm::vec3(0.0f, 1.0f, 0.0f)); + } else { + rotation = _rotation; + } + glm::vec3 normal = rotation * UNROTATED_NORMAL; + plane.setNormal(normal); + plane.setPoint(_position); // the position is definitely a point on our plane + + bool intersects = plane.findRayIntersection(rayInfo); + + if (intersects) { + distance = rayInfo._hitDistance; + + glm::vec3 hitPosition = origin + (distance * direction); + glm::vec3 localHitPosition = glm::inverse(rotation) * (hitPosition - _position); + + // Produce the dimensions of the billboard based on the image's aspect ratio and the overlay's scale. + float maxSize = glm::max(width, height); + glm::vec2 halfDimensions = 0.5f * _scale * glm::vec2(width / maxSize, height / maxSize); + + intersects = -halfDimensions.x <= localHitPosition.x && localHitPosition.x <= halfDimensions.x + && -halfDimensions.y <= localHitPosition.y && localHitPosition.y <= halfDimensions.y; + } + return intersects; } return false; } From e7e7323ff01684262c9ea9fd09913f558dace2e0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 24 Feb 2015 15:00:41 -0800 Subject: [PATCH 19/31] pass 10.9 SDK as CMAKE_OSX_SYSROOT --- CMakeLists.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc67d622de..5deecb4be5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,8 +88,17 @@ endif () set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_CMAKE_PREFIX_PATH}) -# set our OS X deployment target to -set(CMAKE_OSX_DEPLOYMENT_TARGET 10.8) +if (APPLE) + # set our OS X deployment target + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.8) + + # find the 10.9 SDK path + execute_process(COMMAND xcodebuild -sdk -version OUTPUT_VARIABLE XCODE_SDK_VERSIONS) + string(REGEX MATCH \\/.+MacOSX10.9.sdk OSX_SDK_PATH ${XCODE_SDK_VERSIONS}) + + # set that as the SDK to use + set(CMAKE_OSX_SYSROOT ${OSX_SDK_PATH}) +endif () # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) From 8757600a5eeac4199f607992770b118f79b079ee Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Feb 2015 15:57:13 -0800 Subject: [PATCH 20/31] ifdef around massive debug output --- libraries/script-engine/src/ScriptEngine.cpp | 149 ++++++++++--------- 1 file changed, 76 insertions(+), 73 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e99cbea0e5..cbdd59146b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -41,6 +41,13 @@ #include "MIDIEvent.h" + +#ifdef WANT_DEBUG_SCRIPT_ENDING +#define DEBUG_SCRIPT_ENDING(X) X +#else +#define DEBUG_SCRIPT_ENDING(x) +#endif + EntityScriptingInterface ScriptEngine::_entityScriptingInterface; static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ @@ -100,7 +107,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam } ScriptEngine::~ScriptEngine() { - qDebug() << "ScriptEngine::~ScriptEngine() ------- BEGIN ------- script:" << getFilename(); + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::~ScriptEngine() ------- BEGIN ------- script:" << getFilename();) // If we're not already in the middle of stopping all scripts, then we should remove ourselves // from the list of running scripts. We don't do this if we're in the process of stopping all scripts // because that method removes scripts from its list as it iterates them @@ -109,7 +116,7 @@ ScriptEngine::~ScriptEngine() { _allKnownScriptEngines.remove(this); _allScriptsMutex.unlock(); } - qDebug() << "ScriptEngine::~ScriptEngine() ------- END ------- script:" << getFilename(); + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::~ScriptEngine() ------- END ------- script:" << getFilename();) } QSet ScriptEngine::_allKnownScriptEngines; @@ -118,7 +125,7 @@ bool ScriptEngine::_stoppingAllScripts = false; bool ScriptEngine::_doneRunningThisScript = false; void ScriptEngine::stopAllScripts(QObject* application) { - qDebug() << "ScriptEngine::stopAllScripts() ------- BEGIN -------"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() ------- BEGIN -------";) _allScriptsMutex.lock(); _stoppingAllScripts = true; @@ -129,9 +136,9 @@ void ScriptEngine::stopAllScripts(QObject* application) { QString scriptName = scriptEngine->getFilename(); - qDebug() << "ScriptEngine::stopAllScripts() considering:" << scriptName + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() considering:" << scriptName << "isRunning():" << scriptEngine->isRunning() - << "evaluatePending():" << scriptEngine->evaluatePending(); + << "evaluatePending():" << scriptEngine->evaluatePending();) // NOTE: typically all script engines are running. But there's at least one known exception to this, the // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using @@ -144,38 +151,34 @@ void ScriptEngine::stopAllScripts(QObject* application) { while (scriptEngine->evaluatePending()) { QEventLoop loop; QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); - qDebug() << "ScriptEngine::stopAllScripts() while(evaluatePending()) STARTING loop.exec() script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() while(evaluatePending()) STARTING loop.exec() script:" << scriptName;) loop.exec(); - qDebug() << "ScriptEngine::stopAllScripts() while(evaluatePending()) AFTER loop.exec() script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() while(evaluatePending()) AFTER loop.exec() script:" << scriptName;) } } scriptEngine->disconnect(application); scriptEngine->stop(); - qDebug() << "ScriptEngine::stopAllScripts() -- WAITING for waitTillDoneRunning() script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() -- WAITING for waitTillDoneRunning() script:" << scriptName;) scriptEngine->waitTillDoneRunning(); - qDebug() << "ScriptEngine::stopAllScripts() -- AFTER waitTillDoneRunning() script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() -- AFTER waitTillDoneRunning() script:" << scriptName;) i.remove(); } else { } } _stoppingAllScripts = false; _allScriptsMutex.unlock(); - qDebug() << "ScriptEngine::stopAllScripts() ------- DONE -------"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() ------- DONE -------";) } void ScriptEngine::waitTillDoneRunning() { QString scriptName = getFilename(); - qDebug() << "ScriptEngine::waitTillDoneRunning() ------- BEGIN ------- script:" << scriptName; - qDebug() << " _isFinished:" << _isFinished; - qDebug() << " _isRunning:" << _isRunning; - qDebug() << " _isInitialized:" << _isInitialized; - qDebug() << " _evaluatesPending:" << _evaluatesPending; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() ------- BEGIN ------- script:" << scriptName;) if (_isRunning) { - qDebug() << "ScriptEngine::waitTillDoneRunning() SETTING _doneRunningThisScript = false ################################### line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() SETTING _doneRunningThisScript = false ################################### line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) _doneRunningThisScript = false; _isWaitingForDoneRunning = true; @@ -188,23 +191,23 @@ void ScriptEngine::waitTillDoneRunning() { // and run a QEventLoop??? QEventLoop loop; QObject::connect(this, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); - qDebug() << "ScriptEngine::waitTillDoneRunning() STARTING loop.exec() script:" << scriptName; - qDebug() << " _doneRunningThisScript:" << _doneRunningThisScript; - qDebug() << " _isRunning:" << _isRunning; - qDebug() << " _isWaitingForDoneRunning:" << _isWaitingForDoneRunning; - qDebug() << " _isFinished:" << _isFinished; - qDebug() << " _isInitialized:" << _isInitialized; - qDebug() << " _evaluatesPending:" << _evaluatesPending; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() STARTING loop.exec() script:" << scriptName;) + DEBUG_SCRIPT_ENDING(qDebug() << " _doneRunningThisScript:" << _doneRunningThisScript;) + DEBUG_SCRIPT_ENDING(qDebug() << " _isRunning:" << _isRunning;) + DEBUG_SCRIPT_ENDING(qDebug() << " _isWaitingForDoneRunning:" << _isWaitingForDoneRunning;) + DEBUG_SCRIPT_ENDING(qDebug() << " _isFinished:" << _isFinished;) + DEBUG_SCRIPT_ENDING(qDebug() << " _isInitialized:" << _isInitialized;) + DEBUG_SCRIPT_ENDING(qDebug() << " _evaluatesPending:" << _evaluatesPending;) loop.exec(); - qDebug() << "ScriptEngine::waitTillDoneRunning() AFTER loop.exec() script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() AFTER loop.exec() script:" << scriptName;) // process events - qDebug() << "ScriptEngine::waitTillDoneRunning() STARTING QCoreApplication::processEvents() script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() STARTING QCoreApplication::processEvents() script:" << scriptName;) QCoreApplication::processEvents(); - qDebug() << "ScriptEngine::waitTillDoneRunning() AFTER QCoreApplication::processEvents() script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() AFTER QCoreApplication::processEvents() script:" << scriptName;) if (_doneRunningThisScript) { - qDebug() << "ScriptEngine::waitTillDoneRunning() _doneRunningThisScript after processEvents... breaking!!! script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() _doneRunningThisScript after processEvents... breaking!!! script:" << scriptName;) break; } } @@ -212,7 +215,7 @@ void ScriptEngine::waitTillDoneRunning() { _isWaitingForDoneRunning = false; } - qDebug() << "ScriptEngine::waitTillDoneRunning() ------- DONE ------- script:" << scriptName; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() ------- DONE ------- script:" << scriptName;) } QString ScriptEngine::getFilename() const { @@ -430,20 +433,20 @@ void ScriptEngine::evaluate() { return; // bail early } - qDebug() << "ScriptEngine::evaluate() -- BEGIN script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate() -- BEGIN script:" << getFilename() << "[" << this << "]";) if (!_isInitialized) { init(); } - qDebug() << "ScriptEngine::evaluate() -- about to call own evaluate(program) script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate() -- about to call own evaluate(program) script:" << getFilename() << "[" << this << "]";) QScriptValue result = evaluate(_scriptContents); - qDebug() << "ScriptEngine::evaluate() -- AFTER own evaluate(program) script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate() -- AFTER own evaluate(program) script:" << getFilename() << "[" << this << "]";) // TODO: why do we check this twice? It seems like the call to clearExcpetions() in the lower level evaluate call // will cause this code to never actually run... if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); + DEBUG_SCRIPT_ENDING(qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString();) emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); clearExceptions(); } @@ -456,24 +459,24 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN return QScriptValue(); // bail early } - qDebug() << "ScriptEngine::evaluate(program) -- BEGIN script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- BEGIN script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) _evaluatesPending++; - qDebug() << "ScriptEngine::evaluate(program) -- after _evaluatesPending++ script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; - qDebug() << "ScriptEngine::evaluate(program) -- BEFORE QScriptEngine::evaluate() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- after _evaluatesPending++ script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- BEFORE QScriptEngine::evaluate() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); - qDebug() << "ScriptEngine::evaluate(program) -- AFTER QScriptEngine::evaluate() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- AFTER QScriptEngine::evaluate() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString(); } _evaluatesPending--; - qDebug() << "ScriptEngine::evaluate(program) -- after _evaluatesPending-- script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- after _evaluatesPending-- script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) - qDebug() << "ScriptEngine::evaluate(program) -- ABOUT TO emit evaluationFinished() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- ABOUT TO emit evaluationFinished() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) emit evaluationFinished(result, hasUncaughtException()); - qDebug() << "ScriptEngine::evaluate(program) -- AFTER emit evaluationFinished() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- AFTER emit evaluationFinished() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) clearExceptions(); - qDebug() << "ScriptEngine::evaluate(program) -- DONE script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- DONE script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) return result; } @@ -493,18 +496,18 @@ void ScriptEngine::run() { // TODO: can we add a short circuit for _stoppingAllScripts here? What does it mean to not start running if // we're in the process of stopping? - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) if (!_isInitialized) { init(); } - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) _isRunning = true; _isFinished = false; emit runningStateChanged(); - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) QScriptValue result = evaluate(_scriptContents); - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) QElapsedTimer startTime; startTime.start(); @@ -515,11 +518,11 @@ void ScriptEngine::run() { qint64 lastUpdate = usecTimestampNow(); - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) while (!_isFinished) { if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec @@ -528,22 +531,22 @@ void ScriptEngine::run() { } if (_isFinished) { - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) break; } if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } QCoreApplication::processEvents(); if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } if (_isFinished) { - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) break; } @@ -673,34 +676,34 @@ void ScriptEngine::run() { lastUpdate = now; if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } } if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) stopAllTimers(); // make sure all our timers are stopped if the script is ending - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename(); + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename();) if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } emit scriptEnding(); - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) // kill the avatar identity timer delete _avatarIdentityTimer; - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) { @@ -713,43 +716,43 @@ void ScriptEngine::run() { } } - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) // If we were on a thread, then wait till it's done if (thread()) { - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) thread()->quit(); - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } - qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } emit finished(_fileNameString); if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } _isRunning = false; emit runningStateChanged(); - qDebug() << "ABOUT TO emit doneRunning() script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ABOUT TO emit doneRunning() script:" << getFilename() << "[" << this << "]";) emit doneRunning(); - qDebug() << "AFTER emit doneRunning() script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "AFTER emit doneRunning() script:" << getFilename() << "[" << this << "]";) if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } - qDebug() << "ScriptEngine::run() SETTING _doneRunningThisScript = true ################################### line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() SETTING _doneRunningThisScript = true ################################### line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) _doneRunningThisScript = true; if (_isWaitingForDoneRunning) { - qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } } @@ -765,10 +768,10 @@ void ScriptEngine::stopAllTimers() { } void ScriptEngine::stop() { - qDebug() << "ScriptEngine::stop() -- START -- line:" << __LINE__ << " script:" << getFilename(); + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stop() -- START -- line:" << __LINE__ << " script:" << getFilename();) _isFinished = true; emit runningStateChanged(); - qDebug() << "ScriptEngine::stop() -- DONE -- line:" << __LINE__ << " script:" << getFilename(); + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stop() -- DONE -- line:" << __LINE__ << " script:" << getFilename();) } void ScriptEngine::timerFired() { @@ -884,9 +887,9 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac if (contents.isNull()) { qDebug() << "Error loading file: " << url; } else { - qDebug() << "ScriptEngine::include() BEFORE evaluate() line:" << __LINE__ << " parent script:" << getFilename() << "[" << this << "]" << " url:" << url << "_evaluatesPending:" << _evaluatesPending; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::include() BEFORE evaluate() line:" << __LINE__ << " parent script:" << getFilename() << "[" << this << "]" << " url:" << url << "_evaluatesPending:" << _evaluatesPending;) QScriptValue result = evaluate(contents, url.toString()); - qDebug() << "ScriptEngine::include() AFTER evaluate() line:" << __LINE__ << " parent script:" << getFilename() << "[" << this << "]" << " url:" << url << "_evaluatesPending:" << _evaluatesPending; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::include() AFTER evaluate() line:" << __LINE__ << " parent script:" << getFilename() << "[" << this << "]" << " url:" << url << "_evaluatesPending:" << _evaluatesPending;) } } From 89f7f2da2e93df6469d425ff01d7dd38b05043c8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Feb 2015 15:57:34 -0800 Subject: [PATCH 21/31] don't do idle process and painting if we're shutting down the application --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 998e2065dc..537d3d2a75 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1471,6 +1471,10 @@ void Application::checkFPS() { void Application::idle() { PerformanceTimer perfTimer("idle"); + + if (_aboutToQuit) { + return; // bail early, nothing to do here. + } // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing // details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing From 9dcea38b2b661bf38255e6a133a4929deb07db90 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Feb 2015 16:23:39 -0800 Subject: [PATCH 22/31] tweak some debugging --- libraries/script-engine/src/ScriptEngine.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index cbdd59146b..a6b0b8dc1f 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -125,7 +125,7 @@ bool ScriptEngine::_stoppingAllScripts = false; bool ScriptEngine::_doneRunningThisScript = false; void ScriptEngine::stopAllScripts(QObject* application) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() ------- BEGIN -------";) + qDebug() << "ScriptEngine::stopAllScripts() ------- BEGIN -------"; _allScriptsMutex.lock(); _stoppingAllScripts = true; @@ -136,9 +136,7 @@ void ScriptEngine::stopAllScripts(QObject* application) { QString scriptName = scriptEngine->getFilename(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() considering:" << scriptName - << "isRunning():" << scriptEngine->isRunning() - << "evaluatePending():" << scriptEngine->evaluatePending();) + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() considering:" << scriptName << "isRunning():" << scriptEngine->isRunning() << "evaluatePending():" << scriptEngine->evaluatePending();) // NOTE: typically all script engines are running. But there's at least one known exception to this, the // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using @@ -165,11 +163,13 @@ void ScriptEngine::stopAllScripts(QObject* application) { DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() -- AFTER waitTillDoneRunning() script:" << scriptName;) i.remove(); } else { + qDebug() << "ScriptEngine::stopAllScripts() " << scriptName << " - will be freed on it's own."; } } _stoppingAllScripts = false; _allScriptsMutex.unlock(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() ------- DONE -------";) + qDebug() << "ScriptEngine::stopAllScripts() _allKnownScriptEngines.count:" << _allKnownScriptEngines.count(); + qDebug() << "ScriptEngine::stopAllScripts() ------- DONE -------"; } @@ -428,8 +428,8 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func void ScriptEngine::evaluate() { if (_stoppingAllScripts) { - qDebug() << "ScriptEngine::evaluate() while shutting down is ignored..."; - qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate() while shutting down is ignored...";) + DEBUG_SCRIPT_ENDING(qDebug() << " parent script:" << getFilename() << "[" << this << "]";) return; // bail early } @@ -454,8 +454,8 @@ void ScriptEngine::evaluate() { QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { if (_stoppingAllScripts) { - qDebug() << "ScriptEngine::evaluate(program) while shutting down is ignored..."; - qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) while shutting down is ignored...";) + DEBUG_SCRIPT_ENDING(qDebug() << " parent script:" << getFilename() << "[" << this << "]";) return QScriptValue(); // bail early } From 03b10b6cb02fbf281844b02dc3e3b41242e5d0c6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Feb 2015 17:00:30 -0800 Subject: [PATCH 23/31] Add findRayRectangleIntersection --- libraries/shared/src/GeometryUtil.cpp | 35 ++++++++++++++++++++++++++- libraries/shared/src/GeometryUtil.h | 3 +++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index aaec8b3e4a..cf15830a10 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -12,8 +12,10 @@ #include #include -#include "SharedUtil.h" #include "GeometryUtil.h" +#include "PlaneShape.h" +#include "RayIntersectionInfo.h" +#include "SharedUtil.h" glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) { // compute the projection of the point vector onto the segment vector @@ -491,3 +493,34 @@ void PolygonClip::copyCleanArray(int& lengthA, glm::vec2* vertexArrayA, int& len } } } + +bool findRayRectangleIntersection(const glm::vec3& origin, const glm::vec3& direction, + const glm::quat& rotation, const glm::vec3& position, const glm::vec2& dimensions) { + RayIntersectionInfo rayInfo; + rayInfo._rayStart = origin; + rayInfo._rayDirection = direction; + rayInfo._rayLength = std::numeric_limits::max(); + + PlaneShape plane; + + const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f); + glm::vec3 normal = rotation * UNROTATED_NORMAL; + plane.setNormal(normal); + plane.setPoint(position); // the position is definitely a point on our plane + + bool intersects = plane.findRayIntersection(rayInfo); + + if (intersects) { + float distance = rayInfo._hitDistance; + + glm::vec3 hitPosition = origin + (distance * direction); + glm::vec3 localHitPosition = glm::inverse(rotation) * (hitPosition - position); + + glm::vec2 halfDimensions = 0.5f * dimensions; + + intersects = -halfDimensions.x <= localHitPosition.x && localHitPosition.x <= halfDimensions.x + && -halfDimensions.y <= localHitPosition.y && localHitPosition.y <= halfDimensions.y; + } + + return intersects; +} diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index a6889ef73e..e0de536e97 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -76,6 +76,9 @@ bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& directi bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& start, const glm::vec3& end, float radius, float& distance); +bool findRayRectangleIntersection(const glm::vec3& origin, const glm::vec3& direction, + const glm::quat& rotation, const glm::vec3& position, const glm::vec2& dimensions); + bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance); From be7959bbcddb1f45c8e92989ed7cceee18cc4251 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Feb 2015 17:00:55 -0800 Subject: [PATCH 24/31] Fix BillboardOverlay findRayIntersection implementation --- .../src/ui/overlays/BillboardOverlay.cpp | 46 ++++--------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index 4ea0e55710..a82da0ee5f 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -10,9 +10,10 @@ // #include "Application.h" +#include "GeometryUtil.h" +#include "PlaneShape.h" #include "BillboardOverlay.h" -#include BillboardOverlay::BillboardOverlay() : _fromImage(), @@ -192,23 +193,6 @@ bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::v float& distance, BoxFace& face) { if (_texture) { - // This is taken from Planar3DOverlay. Although it probably makes more sense for this - // overlay type to extend from Planar3DOverlay, the interfaces are different enough (scale vs. dimensions) - // that it would break existing scripts and would require other changes to make up for unique - // features like `isFacingAvatar`. - - RayIntersectionInfo rayInfo; - rayInfo._rayStart = origin; - rayInfo._rayDirection = direction; - rayInfo._rayLength = std::numeric_limits::max(); - - bool isNull = _fromImage.isNull(); - float width = isNull ? _texture->getWidth() : _fromImage.width(); - float height = isNull ? _texture->getHeight() : _fromImage.height(); - - PlaneShape plane; - - const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f); glm::quat rotation; if (_isFacingAvatar) { // rotate about vertical to face the camera @@ -217,27 +201,17 @@ bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::v } else { rotation = _rotation; } - glm::vec3 normal = rotation * UNROTATED_NORMAL; - plane.setNormal(normal); - plane.setPoint(_position); // the position is definitely a point on our plane - bool intersects = plane.findRayIntersection(rayInfo); + // Produce the dimensions of the billboard based on the image's aspect ratio and the overlay's scale. + bool isNull = _fromImage.isNull(); + float width = isNull ? _texture->getWidth() : _fromImage.width(); + float height = isNull ? _texture->getHeight() : _fromImage.height(); + float maxSize = glm::max(width, height); + glm::vec2 dimensions = _scale * glm::vec2(width / maxSize, height / maxSize); - if (intersects) { - distance = rayInfo._hitDistance; - - glm::vec3 hitPosition = origin + (distance * direction); - glm::vec3 localHitPosition = glm::inverse(rotation) * (hitPosition - _position); - - // Produce the dimensions of the billboard based on the image's aspect ratio and the overlay's scale. - float maxSize = glm::max(width, height); - glm::vec2 halfDimensions = 0.5f * _scale * glm::vec2(width / maxSize, height / maxSize); - - intersects = -halfDimensions.x <= localHitPosition.x && localHitPosition.x <= halfDimensions.x - && -halfDimensions.y <= localHitPosition.y && localHitPosition.y <= halfDimensions.y; - } - return intersects; + return findRayRectangleIntersection(origin, direction, rotation, _position, dimensions); } + return false; } From eb21b7443989000e1eb495985c12de686e4120d7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Feb 2015 17:01:24 -0800 Subject: [PATCH 25/31] Replace Planar3DOverlay::findRayIntersection with GeometryUtil::findRayRectangleIntersection --- interface/src/ui/overlays/Planar3DOverlay.cpp | 28 ++----------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index 508b5c4227..925725d261 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -17,6 +17,8 @@ #include #include +#include "GeometryUtil.h" + #include "Planar3DOverlay.h" const float DEFAULT_SIZE = 1.0f; @@ -93,29 +95,5 @@ QScriptValue Planar3DOverlay::getProperty(const QString& property) { bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) { - RayIntersectionInfo rayInfo; - rayInfo._rayStart = origin; - rayInfo._rayDirection = direction; - rayInfo._rayLength = std::numeric_limits::max(); - - PlaneShape plane; - - const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f); - glm::vec3 normal = _rotation * UNROTATED_NORMAL; - plane.setNormal(normal); - plane.setPoint(_position); // the position is definitely a point on our plane - - bool intersects = plane.findRayIntersection(rayInfo); - - if (intersects) { - distance = rayInfo._hitDistance; - - glm::vec3 hitPosition = origin + (distance * direction); - glm::vec3 localHitPosition = glm::inverse(_rotation) * (hitPosition - _position); - glm::vec2 halfDimensions = _dimensions / 2.0f; - - intersects = -halfDimensions.x <= localHitPosition.x && localHitPosition.x <= halfDimensions.x - && -halfDimensions.y <= localHitPosition.y && localHitPosition.y <= halfDimensions.y; - } - return intersects; + return findRayRectangleIntersection(origin, direction, _rotation, _position, _dimensions); } From 25ae001d3b874330d3bd538fffab8e66b8fd23eb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Feb 2015 17:05:44 -0800 Subject: [PATCH 26/31] removed extra debugging --- libraries/script-engine/src/ScriptEngine.cpp | 119 +------------------ 1 file changed, 1 insertion(+), 118 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index a6b0b8dc1f..9a88476e8c 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -42,12 +42,6 @@ #include "MIDIEvent.h" -#ifdef WANT_DEBUG_SCRIPT_ENDING -#define DEBUG_SCRIPT_ENDING(X) X -#else -#define DEBUG_SCRIPT_ENDING(x) -#endif - EntityScriptingInterface ScriptEngine::_entityScriptingInterface; static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ @@ -107,7 +101,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam } ScriptEngine::~ScriptEngine() { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::~ScriptEngine() ------- BEGIN ------- script:" << getFilename();) // If we're not already in the middle of stopping all scripts, then we should remove ourselves // from the list of running scripts. We don't do this if we're in the process of stopping all scripts // because that method removes scripts from its list as it iterates them @@ -116,7 +109,6 @@ ScriptEngine::~ScriptEngine() { _allKnownScriptEngines.remove(this); _allScriptsMutex.unlock(); } - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::~ScriptEngine() ------- END ------- script:" << getFilename();) } QSet ScriptEngine::_allKnownScriptEngines; @@ -136,8 +128,6 @@ void ScriptEngine::stopAllScripts(QObject* application) { QString scriptName = scriptEngine->getFilename(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() considering:" << scriptName << "isRunning():" << scriptEngine->isRunning() << "evaluatePending():" << scriptEngine->evaluatePending();) - // NOTE: typically all script engines are running. But there's at least one known exception to this, the // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using // them. We don't need to stop scripts that aren't running. @@ -149,18 +139,14 @@ void ScriptEngine::stopAllScripts(QObject* application) { while (scriptEngine->evaluatePending()) { QEventLoop loop; QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() while(evaluatePending()) STARTING loop.exec() script:" << scriptName;) loop.exec(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() while(evaluatePending()) AFTER loop.exec() script:" << scriptName;) } } scriptEngine->disconnect(application); scriptEngine->stop(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() -- WAITING for waitTillDoneRunning() script:" << scriptName;) scriptEngine->waitTillDoneRunning(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stopAllScripts() -- AFTER waitTillDoneRunning() script:" << scriptName;) i.remove(); } else { qDebug() << "ScriptEngine::stopAllScripts() " << scriptName << " - will be freed on it's own."; @@ -175,10 +161,8 @@ void ScriptEngine::stopAllScripts(QObject* application) { void ScriptEngine::waitTillDoneRunning() { QString scriptName = getFilename(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() ------- BEGIN ------- script:" << scriptName;) if (_isRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() SETTING _doneRunningThisScript = false ################################### line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) _doneRunningThisScript = false; _isWaitingForDoneRunning = true; @@ -191,31 +175,18 @@ void ScriptEngine::waitTillDoneRunning() { // and run a QEventLoop??? QEventLoop loop; QObject::connect(this, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() STARTING loop.exec() script:" << scriptName;) - DEBUG_SCRIPT_ENDING(qDebug() << " _doneRunningThisScript:" << _doneRunningThisScript;) - DEBUG_SCRIPT_ENDING(qDebug() << " _isRunning:" << _isRunning;) - DEBUG_SCRIPT_ENDING(qDebug() << " _isWaitingForDoneRunning:" << _isWaitingForDoneRunning;) - DEBUG_SCRIPT_ENDING(qDebug() << " _isFinished:" << _isFinished;) - DEBUG_SCRIPT_ENDING(qDebug() << " _isInitialized:" << _isInitialized;) - DEBUG_SCRIPT_ENDING(qDebug() << " _evaluatesPending:" << _evaluatesPending;) loop.exec(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() AFTER loop.exec() script:" << scriptName;) // process events - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() STARTING QCoreApplication::processEvents() script:" << scriptName;) QCoreApplication::processEvents(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() AFTER QCoreApplication::processEvents() script:" << scriptName;) if (_doneRunningThisScript) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() _doneRunningThisScript after processEvents... breaking!!! script:" << scriptName;) break; } } _isWaitingForDoneRunning = false; } - - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::waitTillDoneRunning() ------- DONE ------- script:" << scriptName;) } QString ScriptEngine::getFilename() const { @@ -428,25 +399,20 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func void ScriptEngine::evaluate() { if (_stoppingAllScripts) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate() while shutting down is ignored...";) - DEBUG_SCRIPT_ENDING(qDebug() << " parent script:" << getFilename() << "[" << this << "]";) return; // bail early } - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate() -- BEGIN script:" << getFilename() << "[" << this << "]";) if (!_isInitialized) { init(); } - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate() -- about to call own evaluate(program) script:" << getFilename() << "[" << this << "]";) QScriptValue result = evaluate(_scriptContents); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate() -- AFTER own evaluate(program) script:" << getFilename() << "[" << this << "]";) // TODO: why do we check this twice? It seems like the call to clearExcpetions() in the lower level evaluate call // will cause this code to never actually run... if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); - DEBUG_SCRIPT_ENDING(qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString();) + qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); clearExceptions(); } @@ -454,29 +420,18 @@ void ScriptEngine::evaluate() { QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { if (_stoppingAllScripts) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) while shutting down is ignored...";) - DEBUG_SCRIPT_ENDING(qDebug() << " parent script:" << getFilename() << "[" << this << "]";) return QScriptValue(); // bail early } - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- BEGIN script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) _evaluatesPending++; - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- after _evaluatesPending++ script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- BEFORE QScriptEngine::evaluate() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- AFTER QScriptEngine::evaluate() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString(); } _evaluatesPending--; - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- after _evaluatesPending-- script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) - - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- ABOUT TO emit evaluationFinished() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) emit evaluationFinished(result, hasUncaughtException()); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- AFTER emit evaluationFinished() script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) clearExceptions(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::evaluate(program) -- DONE script:" << getFilename() << "_evaluatesPending:" << _evaluatesPending << "[" << this << "]";) return result; } @@ -496,18 +451,14 @@ void ScriptEngine::run() { // TODO: can we add a short circuit for _stoppingAllScripts here? What does it mean to not start running if // we're in the process of stopping? - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) if (!_isInitialized) { init(); } - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) _isRunning = true; _isFinished = false; emit runningStateChanged(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) QScriptValue result = evaluate(_scriptContents); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) QElapsedTimer startTime; startTime.start(); @@ -518,35 +469,19 @@ void ScriptEngine::run() { qint64 lastUpdate = usecTimestampNow(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - while (!_isFinished) { - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec if (usecToSleep > 0) { usleep(usecToSleep); } if (_isFinished) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) break; } - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - QCoreApplication::processEvents(); - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - if (_isFinished) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) break; } @@ -675,37 +610,14 @@ void ScriptEngine::run() { } lastUpdate = now; - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - } - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - stopAllTimers(); // make sure all our timers are stopped if the script is ending - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename();) - - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - emit scriptEnding(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) // kill the avatar identity timer delete _avatarIdentityTimer; - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) { // release the queue of edit entity messages. _entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages(); @@ -716,44 +628,19 @@ void ScriptEngine::run() { } } - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - // If we were on a thread, then wait till it's done if (thread()) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) thread()->quit(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) } emit finished(_fileNameString); - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - _isRunning = false; emit runningStateChanged(); - DEBUG_SCRIPT_ENDING(qDebug() << "ABOUT TO emit doneRunning() script:" << getFilename() << "[" << this << "]";) emit doneRunning(); - DEBUG_SCRIPT_ENDING(qDebug() << "AFTER emit doneRunning() script:" << getFilename() << "[" << this << "]";) - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } - - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() SETTING _doneRunningThisScript = true ################################### line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) _doneRunningThisScript = true; - - if (_isWaitingForDoneRunning) { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::run() ** _isWaitingForDoneRunning == true ** line:" << __LINE__ << " script:" << getFilename() << "[" << this << "]";) - } } // NOTE: This is private because it must be called on the same thread that created the timers, which is why @@ -768,10 +655,8 @@ void ScriptEngine::stopAllTimers() { } void ScriptEngine::stop() { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stop() -- START -- line:" << __LINE__ << " script:" << getFilename();) _isFinished = true; emit runningStateChanged(); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::stop() -- DONE -- line:" << __LINE__ << " script:" << getFilename();) } void ScriptEngine::timerFired() { @@ -887,9 +772,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac if (contents.isNull()) { qDebug() << "Error loading file: " << url; } else { - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::include() BEFORE evaluate() line:" << __LINE__ << " parent script:" << getFilename() << "[" << this << "]" << " url:" << url << "_evaluatesPending:" << _evaluatesPending;) QScriptValue result = evaluate(contents, url.toString()); - DEBUG_SCRIPT_ENDING(qDebug() << "ScriptEngine::include() AFTER evaluate() line:" << __LINE__ << " parent script:" << getFilename() << "[" << this << "]" << " url:" << url << "_evaluatesPending:" << _evaluatesPending;) } } From eab09eaf2885de695dc9780f95c63d916085f3b4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Feb 2015 17:15:58 -0800 Subject: [PATCH 27/31] removed extra debugging --- interface/src/Application.cpp | 14 ++-------- libraries/script-engine/src/ScriptEngine.cpp | 27 ++++++-------------- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 537d3d2a75..390b42eaa7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3567,11 +3567,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, bool activateMainWindow) { - qDebug() << "Application::loadScript() ---- BEGIN ---- Script:" << scriptFilename; - if (isAboutToQuit()) { - qDebug() << "Requests to load scripts while quitting are ignored. Script:" << scriptFilename; - qDebug() << "Application::loadScript() ---- END ---- Script:" << scriptFilename; return NULL; } @@ -3580,8 +3576,6 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor && !_scriptEnginesHash[scriptURLString]->isFinished()) { - qDebug() << "Application::loadScript() from _scriptEnginesHash[scriptURLString].... Script:" << scriptFilename; - qDebug() << "Application::loadScript() ---- END ---- Script:" << scriptFilename; return _scriptEnginesHash[scriptURLString]; } @@ -3600,7 +3594,6 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &Application::handleScriptLoadError); // get the script engine object to load the script at the designated script URL - qDebug() << "Application::loadScript() about to call loadURL() scriptUrl:" << scriptUrl; scriptEngine->loadURL(scriptUrl); } @@ -3609,9 +3602,6 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser _window->activateWindow(); } - qDebug() << "Application::loadScript() newly created scriptEngine.... Script:" << scriptFilename; - qDebug() << "Application::loadScript() ---- END ---- Script:" << scriptFilename; - return scriptEngine; } @@ -3771,8 +3761,8 @@ void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject voxelWalletUUID = QUuid(voxelObject[VOXEL_WALLET_UUID].toString()); } - qDebug() << "Voxel costs are" << satoshisPerVoxel << "per voxel and" << satoshisPerMeterCubed << "per meter cubed"; - qDebug() << "Destination wallet UUID for voxel payments is" << voxelWalletUUID; + qDebug() << "Octree edits costs are" << satoshisPerVoxel << "per octree cell and" << satoshisPerMeterCubed << "per meter cubed"; + qDebug() << "Destination wallet UUID for edit payments is" << voxelWalletUUID; } QString Application::getPreviousScriptLocation() { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 9a88476e8c..d090fc0ac6 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -117,8 +117,6 @@ bool ScriptEngine::_stoppingAllScripts = false; bool ScriptEngine::_doneRunningThisScript = false; void ScriptEngine::stopAllScripts(QObject* application) { - qDebug() << "ScriptEngine::stopAllScripts() ------- BEGIN -------"; - _allScriptsMutex.lock(); _stoppingAllScripts = true; @@ -148,14 +146,10 @@ void ScriptEngine::stopAllScripts(QObject* application) { scriptEngine->waitTillDoneRunning(); i.remove(); - } else { - qDebug() << "ScriptEngine::stopAllScripts() " << scriptName << " - will be freed on it's own."; } } _stoppingAllScripts = false; _allScriptsMutex.unlock(); - qDebug() << "ScriptEngine::stopAllScripts() _allKnownScriptEngines.count:" << _allKnownScriptEngines.count(); - qDebug() << "ScriptEngine::stopAllScripts() ------- DONE -------"; } @@ -693,8 +687,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) { if (_stoppingAllScripts) { - qDebug() << "Script.setInterval() while shutting down is ignored..."; - qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + qDebug() << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename(); return NULL; // bail early } @@ -703,8 +696,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { if (_stoppingAllScripts) { - qDebug() << "Script.setTimeout() while shutting down is ignored..."; - qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + qDebug() << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename(); return NULL; // bail early } @@ -754,9 +746,8 @@ void ScriptEngine::print(const QString& message) { // all of the files have finished loading. void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) { if (_stoppingAllScripts) { - qDebug() << "Script.include() while shutting down is ignored..."; - qDebug() << " includeFiles:" << includeFiles; - qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + qDebug() << "Script.include() while shutting down is ignored..." + << "includeFiles:" << includeFiles << "parent script:" << getFilename(); return; // bail early } QList urls; @@ -799,9 +790,8 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { if (_stoppingAllScripts) { - qDebug() << "Script.include() while shutting down is ignored..."; - qDebug() << " includeFile:" << includeFile; - qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + qDebug() << "Script.include() while shutting down is ignored... " + << "includeFile:" << includeFile << "parent script:" << getFilename(); return; // bail early } @@ -815,9 +805,8 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { // the Application or other context will connect to in order to know to actually load the script void ScriptEngine::load(const QString& loadFile) { if (_stoppingAllScripts) { - qDebug() << "Script.load() while shutting down is ignored..."; - qDebug() << " loadFile:" << loadFile; - qDebug() << " parent script:" << getFilename() << "[" << this << "]"; + qDebug() << "Script.load() while shutting down is ignored... " + << "loadFile:" << loadFile << "parent script:" << getFilename(); return; // bail early } From 0456cb298f35070346e9d9572b9d786f7bda0bac Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Feb 2015 17:16:00 -0800 Subject: [PATCH 28/31] lower threshold for ignoring rotation updates one hundred fold smaller --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 15d46603b5..d6a3aab970 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1002,7 +1002,7 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) const { } const float MIN_POSITION_DELTA = 0.0001f; -const float MIN_ALIGNMENT_DOT = 0.9999f; +const float MIN_ALIGNMENT_DOT = 0.999999f; const float MIN_VELOCITY_DELTA = 0.01f; const float MIN_DAMPING_DELTA = 0.001f; const float MIN_GRAVITY_DELTA = 0.001f; From 310654831c6f663e5745a6f66f7642ebeb3dac9e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Feb 2015 17:34:19 -0800 Subject: [PATCH 29/31] clean up comments remove dead code --- interface/src/Application.cpp | 6 ++--- .../src/EntityTreeRenderer.cpp | 14 ++++++------ libraries/script-engine/src/ScriptEngine.cpp | 22 +++++++++++++++---- libraries/script-engine/src/ScriptEngine.h | 1 - 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 390b42eaa7..d3161ebf51 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3541,6 +3541,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance()); #endif + // TODO: Consider moving some of this functionality into the ScriptEngine class instead. It seems wrong that this + // work is being done in the Application class when really these dependencies are more related to the ScriptEngine's + // implementation QThread* workerThread = new QThread(this); QString scriptEngineName = QString("Script Thread:") + scriptEngine->getFilename(); workerThread->setObjectName(scriptEngineName); @@ -3552,9 +3555,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri connect(scriptEngine, SIGNAL(doneRunning()), scriptEngine, SLOT(deleteLater())); connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); - // when the application is about to quit, stop our script engine so it unwinds properly - //connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop())); - auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::nodeKilled, scriptEngine, &ScriptEngine::nodeKilled); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 8648cea285..70e1054c39 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -59,14 +59,14 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf } EntityTreeRenderer::~EntityTreeRenderer() { - // NOTE: we don't need to delete _entitiesScriptEngine because it's owned by the application and gets cleaned up - // automatically but we do need to delete our sandbox script engine. + // NOTE: we don't need to delete _entitiesScriptEngine because it is registered with the application and has a + // signal tied to call it's deleteLater on doneRunning if (_sandboxScriptEngine) { - // NOTE: is it possible this is a problem? I think that we hook the script engine object up to a deleteLater() - // call inside of registerScriptEngineWithApplicationServices() but do we not call that for _sandboxScriptEngine??? - // this _sandboxScriptEngine implementation is confusing and potentially error prone because it's not a full fledged - // ScriptEngine that has been fully connected. We did this so that scripts that were ill-formed could be evaluated - // but not execute against the application. + // TODO: consider reworking how _sandboxScriptEngine is managed. It's treated differently than _entitiesScriptEngine + // because we don't call registerScriptEngineWithApplicationServices() for it. This implementation is confusing and + // potentially error prone because it's not a full fledged ScriptEngine that has been fully connected to the + // application. We did this so that scripts that were ill-formed could be evaluated but not execute against the + // application services. But this means it's shutdown behavior is different from other ScriptEngines delete _sandboxScriptEngine; _sandboxScriptEngine = NULL; } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index d090fc0ac6..b41331450b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -135,16 +135,31 @@ void ScriptEngine::stopAllScripts(QObject* application) { // complete. After that we can handle the stop process appropriately if (scriptEngine->evaluatePending()) { while (scriptEngine->evaluatePending()) { + + // This event loop allows any started, but not yet finished evaluate() calls to complete + // we need to let these complete so that we can be guaranteed that the script engine isn't + // in a partially setup state, which can confuse our shutdown unwinding. QEventLoop loop; QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); loop.exec(); } } + // We disconnect any script engine signals from the application because we don't want to do any + // extra stopScript/loadScript processing that the Application normally does when scripts start + // and stop. We can safely short circuit this because we know we're in the "quitting" process scriptEngine->disconnect(application); + + // Calling stop on the script engine will set it's internal _isFinished state to true, and result + // in the ScriptEngine gracefully ending it's run() method. scriptEngine->stop(); + // We need to wait for the engine to be done running before we proceed, because we don't + // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing + // any application state after we leave this stopAllScripts() method scriptEngine->waitTillDoneRunning(); + + // If the script is stopped, we can remove it from our set i.remove(); } } @@ -156,10 +171,11 @@ void ScriptEngine::stopAllScripts(QObject* application) { void ScriptEngine::waitTillDoneRunning() { QString scriptName = getFilename(); + // If the script never started running or finished running before we got here, we don't need to wait for it if (_isRunning) { - _doneRunningThisScript = false; - _isWaitingForDoneRunning = true; + _doneRunningThisScript = false; // NOTE: this is static, we serialize our waiting for scripts to finish + // What can we do here??? // we will be calling this on the main Application thread, inside of stopAllScripts() // we want the application thread to continue to process events, because the script will @@ -178,8 +194,6 @@ void ScriptEngine::waitTillDoneRunning() { break; } } - - _isWaitingForDoneRunning = false; } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 51cacd5e58..154fdb88e3 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -136,7 +136,6 @@ protected: bool _isFinished; bool _isRunning; int _evaluatesPending = 0; - bool _isWaitingForDoneRunning = false; bool _isInitialized; bool _isAvatar; QTimer* _avatarIdentityTimer; From f1017f8a5d56cbaab111f7609623163b0eb0b69f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Feb 2015 17:45:22 -0800 Subject: [PATCH 30/31] simplify waitTillDoneRunning --- libraries/script-engine/src/ScriptEngine.cpp | 21 ++++++-------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index b41331450b..d201c1568c 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -176,23 +176,14 @@ void ScriptEngine::waitTillDoneRunning() { _doneRunningThisScript = false; // NOTE: this is static, we serialize our waiting for scripts to finish - // What can we do here??? - // we will be calling this on the main Application thread, inside of stopAllScripts() - // we want the application thread to continue to process events, because the script will - // likely need to marshall messages across to the main thread. - while (!_doneRunningThisScript && _isRunning) { + // NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts() + // we want the application thread to continue to process events, because the scripts will likely need to + // marshall messages across to the main thread. For example if they access Settings or Meny in any of their + // shutdown code. + while (!_doneRunningThisScript) { - // and run a QEventLoop??? - QEventLoop loop; - QObject::connect(this, &ScriptEngine::doneRunning, &loop, &QEventLoop::quit); - loop.exec(); - - // process events + // process events for the main application thread, allowing invokeMethod calls to pass between threads QCoreApplication::processEvents(); - - if (_doneRunningThisScript) { - break; - } } } } From e87df0017a0769ed6d8a4a86ac59cc9c7814e1d3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 25 Feb 2015 08:26:54 -0800 Subject: [PATCH 31/31] code review feedback --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 70e1054c39..46f9ff6f55 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -890,8 +890,8 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID) { if (_tree && !_shuttingDown) { checkAndCallUnload(entityID); + checkAndCallPreload(entityID); } - checkAndCallPreload(entityID); } void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) {