first cut at shutting down scripts ahead of other cleanup

This commit is contained in:
ZappoMan 2015-02-20 15:28:25 -08:00
parent 70400f7f8c
commit 0b607fa390
5 changed files with 270 additions and 148 deletions

View file

@ -527,12 +527,22 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
} }
void Application::aboutToQuit() { void Application::aboutToQuit() {
qDebug() << "Application::aboutToQuit()";
_aboutToQuit = true; _aboutToQuit = true;
cleanupBeforeQuit(); cleanupBeforeQuit();
} }
void Application::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 // first stop all timers directly or by invokeMethod
// depending on what thread they run in // depending on what thread they run in
locationUpdateTimer->stop(); locationUpdateTimer->stop();
@ -572,6 +582,8 @@ void Application::cleanupBeforeQuit() {
// destroy the AudioClient so it and its thread have a chance to go down safely // destroy the AudioClient so it and its thread have a chance to go down safely
DependencyManager::destroy<AudioClient>(); DependencyManager::destroy<AudioClient>();
qDebug() << "Application::cleanupBeforeQuit() ------------ DONE -----------------";
} }
Application::~Application() { Application::~Application() {
@ -3432,6 +3444,7 @@ void Application::clearScriptsBeforeRunning() {
} }
void Application::saveScripts() { void Application::saveScripts() {
qDebug() << "Application::saveScripts()";
// Saves all currently running user-loaded scripts // Saves all currently running user-loaded scripts
Settings settings; Settings settings;
settings.beginWriteArray(SETTINGS_KEY); settings.beginWriteArray(SETTINGS_KEY);
@ -3525,7 +3538,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
#endif #endif
QThread* workerThread = new QThread(this); 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.. // when the worker thread is started, call our engine's run..
connect(workerThread, &QThread::started, scriptEngine, &ScriptEngine::run); connect(workerThread, &QThread::started, scriptEngine, &ScriptEngine::run);
@ -3599,6 +3613,7 @@ void Application::handleScriptLoadError(const QString& scriptFilename) {
} }
void Application::scriptFinished(const QString& scriptName) { void Application::scriptFinished(const QString& scriptName) {
qDebug() << "Application::scriptFinished(), scriptName:" << scriptName;
const QString& scriptURLString = QUrl(scriptName).toString(); const QString& scriptURLString = QUrl(scriptName).toString();
QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptURLString); QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptURLString);
if (it != _scriptEnginesHash.end()) { if (it != _scriptEnginesHash.end()) {
@ -3609,6 +3624,7 @@ void Application::scriptFinished(const QString& scriptName) {
} }
void Application::stopAllScripts(bool restart) { void Application::stopAllScripts(bool restart) {
qDebug() << "Application::stopAllScripts()... restart:" << restart;
// stops all current running scripts // stops all current running scripts
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin(); for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
it != _scriptEnginesHash.constEnd(); it++) { it != _scriptEnginesHash.constEnd(); it++) {

View file

@ -97,6 +97,27 @@ void EntityTreeRenderer::init() {
connect(entityTree, &EntityTree::changingEntityID, this, &EntityTreeRenderer::changingEntityID); 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) { QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) {
EntityItem* entity = static_cast<EntityTree*>(_tree)->findEntityByEntityItemID(entityItemID); EntityItem* entity = static_cast<EntityTree*>(_tree)->findEntityByEntityItemID(entityItemID);
return loadEntityScript(entity); return loadEntityScript(entity);
@ -156,6 +177,10 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe
QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) { QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) {
if (_shuttingDown) {
return QScriptValue(); // no entity...
}
if (!entity) { if (!entity) {
return QScriptValue(); // no entity... return QScriptValue(); // no entity...
} }
@ -235,7 +260,7 @@ void EntityTreeRenderer::setTree(Octree* newTree) {
} }
void EntityTreeRenderer::update() { void EntityTreeRenderer::update() {
if (_tree) { if (_tree && !_shuttingDown) {
EntityTree* tree = static_cast<EntityTree*>(_tree); EntityTree* tree = static_cast<EntityTree*>(_tree);
tree->update(); tree->update();
@ -258,7 +283,7 @@ void EntityTreeRenderer::update() {
} }
void EntityTreeRenderer::checkEnterLeaveEntities() { void EntityTreeRenderer::checkEnterLeaveEntities() {
if (_tree) { if (_tree && !_shuttingDown) {
_tree->lockForWrite(); // so that our scripts can do edits if they want _tree->lockForWrite(); // so that our scripts can do edits if they want
glm::vec3 avatarPosition = _viewState->getAvatarPosition() / (float) TREE_SCALE; glm::vec3 avatarPosition = _viewState->getAvatarPosition() / (float) TREE_SCALE;
@ -309,7 +334,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
} }
void EntityTreeRenderer::leaveAllEntities() { void EntityTreeRenderer::leaveAllEntities() {
if (_tree) { if (_tree && !_shuttingDown) {
_tree->lockForWrite(); // so that our scripts can do edits if they want _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 // 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) { void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) {
if (_tree) { if (_tree && !_shuttingDown) {
Model::startScene(renderSide); Model::startScene(renderSide);
RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 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) { void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); if (_tree && !_shuttingDown) {
PickRay ray = _viewState->computePickRay(event->x(), event->y()); PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent");
PickRay ray = _viewState->computePickRay(event->x(), event->y());
bool precisionPicking = !_dontDoPrecisionPicking; bool precisionPicking = !_dontDoPrecisionPicking;
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking);
if (rayPickResult.intersects) { if (rayPickResult.intersects) {
//qDebug() << "mousePressEvent over entity:" << rayPickResult.entityID; //qDebug() << "mousePressEvent over entity:" << rayPickResult.entityID;
emit mousePressOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); emit mousePressOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID));
QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
QScriptValue entityScript = loadEntityScript(rayPickResult.entity); QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
if (entityScript.property("mousePressOnEntity").isValid()) { if (entityScript.property("mousePressOnEntity").isValid()) {
entityScript.property("mousePressOnEntity").call(entityScript, entityScriptArgs); entityScript.property("mousePressOnEntity").call(entityScript, entityScriptArgs);
} }
_currentClickingOnEntityID = rayPickResult.entityID; _currentClickingOnEntityID = rayPickResult.entityID;
emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID));
if (entityScript.property("clickDownOnEntity").isValid()) { if (entityScript.property("clickDownOnEntity").isValid()) {
entityScript.property("clickDownOnEntity").call(entityScript, entityScriptArgs); 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) { void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent"); if (_tree && !_shuttingDown) {
PickRay ray = _viewState->computePickRay(event->x(), event->y()); PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent");
bool precisionPicking = !_dontDoPrecisionPicking; PickRay ray = _viewState->computePickRay(event->x(), event->y());
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); bool precisionPicking = !_dontDoPrecisionPicking;
if (rayPickResult.intersects) { RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking);
//qDebug() << "mouseReleaseEvent over entity:" << rayPickResult.entityID; if (rayPickResult.intersects) {
emit mouseReleaseOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); //qDebug() << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
emit mouseReleaseOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID));
QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
QScriptValue entityScript = loadEntityScript(rayPickResult.entity); QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
if (entityScript.property("mouseReleaseOnEntity").isValid()) { if (entityScript.property("mouseReleaseOnEntity").isValid()) {
entityScript.property("mouseReleaseOnEntity").call(entityScript, entityScriptArgs); entityScript.property("mouseReleaseOnEntity").call(entityScript, entityScriptArgs);
}
} }
}
// Even if we're no longer intersecting with an entity, if we started clicking on it, and now // 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 // we're releasing the button, then this is considered a clickOn event
if (!_currentClickingOnEntityID.isInvalidID()) { if (!_currentClickingOnEntityID.isInvalidID()) {
emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID));
QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID);
QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID);
if (currentClickingEntity.property("clickReleaseOnEntity").isValid()) { if (currentClickingEntity.property("clickReleaseOnEntity").isValid()) {
currentClickingEntity.property("clickReleaseOnEntity").call(currentClickingEntity, currentClickingEntityArgs); currentClickingEntity.property("clickReleaseOnEntity").call(currentClickingEntity, currentClickingEntityArgs);
}
} }
}
// makes it the unknown ID, we just released so we can't be clicking on anything // makes it the unknown ID, we just released so we can't be clicking on anything
_currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); _currentClickingOnEntityID = EntityItemID::createInvalidEntityID();
_lastMouseEvent = MouseEvent(*event, deviceID); _lastMouseEvent = MouseEvent(*event, deviceID);
_lastMouseEventValid = true; _lastMouseEventValid = true;
}
} }
void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { 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 bool precisionPicking = false; // for mouse moves we do not do precision picking
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
if (rayPickResult.intersects) { if (rayPickResult.intersects) {
QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
// load the entity script if needed... // load the entity script if needed...
QScriptValue entityScript = loadEntityScript(rayPickResult.entity); QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
if (entityScript.property("mouseMoveEvent").isValid()) { if (entityScript.property("mouseMoveEvent").isValid()) {
entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs);
} }
//qDebug() << "mouseMoveEvent over entity:" << rayPickResult.entityID; //qDebug() << "mouseMoveEvent over entity:" << rayPickResult.entityID;
emit mouseMoveOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); emit mouseMoveOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID));
if (entityScript.property("mouseMoveOnEntity").isValid()) { if (entityScript.property("mouseMoveOnEntity").isValid()) {
entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); 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 // 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. // then we need to send the hover leave.
if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) { if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) {
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID)); emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID));
QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID); QScriptValueList currentHoverEntityArgs = createMouseEventArgs(_currentHoverOverEntityID, event, deviceID);
QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID);
if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { if (currentHoverEntity.property("hoverLeaveEntity").isValid()) {
currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); 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 // 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 // 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 // not yet released the hold then this is still considered a holdingClickOnEntity event
if (!_currentClickingOnEntityID.isInvalidID()) { if (!_currentClickingOnEntityID.isInvalidID()) {
emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID));
QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID);
QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID);
if (currentClickingEntity.property("holdingClickOnEntity").isValid()) { if (currentClickingEntity.property("holdingClickOnEntity").isValid()) {
currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs); currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs);
}
} }
_lastMouseEvent = MouseEvent(*event, deviceID);
_lastMouseEventValid = true;
} }
_lastMouseEvent = MouseEvent(*event, deviceID);
_lastMouseEventValid = true;
} }
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
checkAndCallUnload(entityID); if (_tree && !_shuttingDown) {
checkAndCallUnload(entityID);
}
_entityScripts.remove(entityID); _entityScripts.remove(entityID);
} }
void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID) { void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID) {
checkAndCallUnload(entityID); if (_tree && !_shuttingDown) {
checkAndCallUnload(entityID);
}
checkAndCallPreload(entityID); checkAndCallPreload(entityID);
} }
void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) { void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) {
// load the entity script if needed... if (_tree && !_shuttingDown) {
QScriptValue entityScript = loadEntityScript(entityID); // load the entity script if needed...
if (entityScript.property("preload").isValid()) { QScriptValue entityScript = loadEntityScript(entityID);
QScriptValueList entityArgs = createEntityArgs(entityID); if (entityScript.property("preload").isValid()) {
entityScript.property("preload").call(entityScript, entityArgs); QScriptValueList entityArgs = createEntityArgs(entityID);
entityScript.property("preload").call(entityScript, entityArgs);
}
} }
} }
void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) {
QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID); if (_tree && !_shuttingDown) {
if (entityScript.property("unload").isValid()) { QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID);
QScriptValueList entityArgs = createEntityArgs(entityID); if (entityScript.property("unload").isValid()) {
entityScript.property("unload").call(entityScript, entityArgs); 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, void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,
const Collision& collision) { const Collision& collision) {
QScriptValue entityScriptA = loadEntityScript(idA); if (_tree && !_shuttingDown) {
if (entityScriptA.property("collisionWithEntity").isValid()) { QScriptValue entityScriptA = loadEntityScript(idA);
QScriptValueList args; if (entityScriptA.property("collisionWithEntity").isValid()) {
args << idA.toScriptValue(_entitiesScriptEngine); QScriptValueList args;
args << idB.toScriptValue(_entitiesScriptEngine); args << idA.toScriptValue(_entitiesScriptEngine);
args << collisionToScriptValue(_entitiesScriptEngine, collision); args << idB.toScriptValue(_entitiesScriptEngine);
entityScriptA.property("collisionWithEntity").call(entityScriptA, args); args << collisionToScriptValue(_entitiesScriptEngine, collision);
} entityScriptA.property("collisionWithEntity").call(entityScriptA, args);
}
QScriptValue entityScriptB = loadEntityScript(idB); QScriptValue entityScriptB = loadEntityScript(idB);
if (entityScriptB.property("collisionWithEntity").isValid()) { if (entityScriptB.property("collisionWithEntity").isValid()) {
QScriptValueList args; QScriptValueList args;
args << idB.toScriptValue(_entitiesScriptEngine); args << idB.toScriptValue(_entitiesScriptEngine);
args << idA.toScriptValue(_entitiesScriptEngine); args << idA.toScriptValue(_entitiesScriptEngine);
args << collisionToScriptValue(_entitiesScriptEngine, collision); args << collisionToScriptValue(_entitiesScriptEngine, collision);
entityScriptB.property("collisionWithEntity").call(entityScriptA, args); entityScriptB.property("collisionWithEntity").call(entityScriptA, args);
}
} }
} }

View file

@ -46,6 +46,7 @@ public:
virtual int getBoundaryLevelAdjust() const; virtual int getBoundaryLevelAdjust() const;
virtual void setTree(Octree* newTree); virtual void setTree(Octree* newTree);
void shutdown();
void update(); void update();
EntityTree* getTree() { return static_cast<EntityTree*>(_tree); } EntityTree* getTree() { return static_cast<EntityTree*>(_tree); }
@ -154,6 +155,8 @@ private:
bool _displayModelElementProxy; bool _displayModelElementProxy;
bool _dontDoPrecisionPicking; bool _dontDoPrecisionPicking;
bool _shuttingDown = false;
}; };
#endif // hifi_EntityTreeRenderer_h #endif // hifi_EntityTreeRenderer_h

View file

@ -94,8 +94,45 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
_isUserLoaded(false), _isUserLoaded(false),
_arrayBufferClass(new ArrayBufferClass(this)) _arrayBufferClass(new ArrayBufferClass(this))
{ {
_allKnownScriptEngines.insert(this);
} }
ScriptEngine::~ScriptEngine() {
qDebug() << "[" << QThread::currentThread() << "]" << "ScriptEngine::~ScriptEngine() " << getFilename();
_allKnownScriptEngines.remove(this);
}
QSet<ScriptEngine*> 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) { void ScriptEngine::setIsAvatar(bool isAvatar) {
_isAvatar = isAvatar; _isAvatar = isAvatar;
@ -364,16 +401,18 @@ void ScriptEngine::run() {
} }
if (_isFinished) { if (_isFinished) {
qDebug() << "ScriptEngine::run()... while() about to break " << getFilename();
break; break;
} }
QCoreApplication::processEvents(); QCoreApplication::processEvents();
if (_isFinished) { if (_isFinished) {
qDebug() << "ScriptEngine::run()... while() about to break " << getFilename();
break; break;
} }
if (_entityScriptingInterface.getEntityPacketSender()->serversExist()) { if (!_isFinished && _entityScriptingInterface.getEntityPacketSender()->serversExist()) {
// release the queue of edit entity messages. // release the queue of edit entity messages.
_entityScriptingInterface.getEntityPacketSender()->releaseQueuedMessages(); _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) const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * AudioConstants::SAMPLE_RATE)
/ (1000 * 1000)) + 0.5); / (1000 * 1000)) + 0.5);
@ -493,9 +532,13 @@ void ScriptEngine::run() {
clearExceptions(); clearExceptions();
} }
emit update(deltaTime); if (!_isFinished) {
//qDebug() << "ScriptEngine::run()... about to emit update() _scriptName:" << _scriptName << "_fileNameString:" << _fileNameString << "_isFinished:" << _isFinished;
emit update(deltaTime);
}
lastUpdate = now; lastUpdate = now;
} }
qDebug() << "ScriptEngine::run()... about to emit scriptEnding() " << getFilename();
emit scriptEnding(); emit scriptEnding();
// kill the avatar identity timer // 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 we were on a thread, then wait till it's done
if (thread()) { if (thread()) {
qDebug() << "ScriptEngine::run()... about to call thread()->quit() " << getFilename();
thread()->quit(); thread()->quit();
} }
qDebug() << "ScriptEngine::run()... about to emit finished() " << getFilename();
emit finished(_fileNameString); emit finished(_fileNameString);
_isRunning = false; _isRunning = false;
qDebug() << "ScriptEngine::run()... about to emit runningStateChanged() " << getFilename();
emit runningStateChanged(); emit runningStateChanged();
qDebug() << "ScriptEngine::run()... about to emit doneRunning() " << getFilename();
emit doneRunning();
qDebug() << "ScriptEngine::run()... DONE WITH run()... " << getFilename();
} }
void ScriptEngine::stop() { void ScriptEngine::stop() {
qDebug() << "ScriptEngine::stop()... " << getFilename();
_isFinished = true; _isFinished = true;
emit runningStateChanged(); emit runningStateChanged();
} }

View file

@ -43,6 +43,8 @@ public:
const QString& fileNameString = QString(""), const QString& fileNameString = QString(""),
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
~ScriptEngine();
/// Access the EntityScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener /// Access the EntityScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
static EntityScriptingInterface* getEntityScriptingInterface() { return &_entityScriptingInterface; } static EntityScriptingInterface* getEntityScriptingInterface() { return &_entityScriptingInterface; }
@ -88,6 +90,10 @@ public:
bool isUserLoaded() const { return _isUserLoaded; } bool isUserLoaded() const { return _isUserLoaded; }
void setParentURL(const QString& parentURL) { _parentURL = parentURL; } void setParentURL(const QString& parentURL) { _parentURL = parentURL; }
QString getFilename() const;
static void gracefullyStopAllScripts();
public slots: public slots:
void loadURL(const QUrl& scriptURL); void loadURL(const QUrl& scriptURL);
@ -118,6 +124,7 @@ signals:
void runningStateChanged(); void runningStateChanged();
void evaluationFinished(QScriptValue result, bool isException); void evaluationFinished(QScriptValue result, bool isException);
void loadScript(const QString& scriptName, bool isUserLoaded); void loadScript(const QString& scriptName, bool isUserLoaded);
void doneRunning();
protected: protected:
QString _scriptContents; QString _scriptContents;
@ -156,6 +163,9 @@ private:
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers; QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
private slots: private slots:
void handleScriptDownload(); void handleScriptDownload();
private:
static QSet<ScriptEngine*> _allKnownScriptEngines;
}; };
#endif // hifi_ScriptEngine_h #endif // hifi_ScriptEngine_h