Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 1298 files). Show all
Unified · Split
| @@ -224,7 +224,7 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const · 223 unmodified lines | |||
| 224 | if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { | 224 | if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { |
| 225 | QObject::connect(this, &ScriptEngine::update, this, [this]() { | 225 | QObject::connect(this, &ScriptEngine::update, this, [this]() { |
| 226 | // process pending entity script content | 226 | // process pending entity script content |
| 227 | if (!_contentAvailableQueue.empty()) { | 227 | if (!_contentAvailableQueue.empty() && !(_isFinished || _isStopping)) { |
| 228 | EntityScriptContentAvailableMap pending; | 228 | EntityScriptContentAvailableMap pending; |
| 229 | std::swap(_contentAvailableQueue, pending); | 229 | std::swap(_contentAvailableQueue, pending); |
| 230 | for (auto& pair : pending) { | 230 | for (auto& pair : pending) { |
| @@ -343,7 +343,7 @@ void ScriptEngine::runDebuggable() { · 112 unmodified lines | |||
| 343 | // we check for 'now' in the past in case people set their clock back | 343 | // we check for 'now' in the past in case people set their clock back |
| 344 | if (_lastUpdate < now) { | 344 | if (_lastUpdate < now) { |
| 345 | float deltaTime = (float)(now - _lastUpdate) / (float)USECS_PER_SECOND; | 345 | float deltaTime = (float)(now - _lastUpdate) / (float)USECS_PER_SECOND; |
| 346 | if (!_isFinished) { | 346 | if (!(_isFinished || _isStopping)) { |
| 347 | emit update(deltaTime); | 347 | emit update(deltaTime); |
| 348 | } | 348 | } |
| 349 | } | 349 | } |
| @@ -397,15 +397,41 @@ void ScriptEngine::executeOnScriptThread(std::function<void()> function, const Q · 47 unmodified lines | |||
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | void ScriptEngine::waitTillDoneRunning() { | 399 | void ScriptEngine::waitTillDoneRunning() { |
| 400 | // Engine should be stopped already, but be defensive | ||
| 401 | stop(); | ||
| 402 | |||
| 400 | auto workerThread = thread(); | 403 | auto workerThread = thread(); |
| 401 | 404 | ||
| 405 | if (workerThread == QThread::currentThread()) { | ||
| 406 | qCWarning(scriptengine) << "ScriptEngine::waitTillDoneRunning called, but the script is on the same thread:" << getFilename(); | ||
| 407 | return; | ||
| 408 | } | ||
| 409 | |||
| 402 | if (_isThreaded && workerThread) { | 410 | if (_isThreaded && workerThread) { |
| 403 | // We should never be waiting (blocking) on our own thread | 411 | // We should never be waiting (blocking) on our own thread |
| 404 | assert(workerThread != QThread::currentThread()); | 412 | assert(workerThread != QThread::currentThread()); |
| 405 | 413 | ||
| 406 | // Engine should be stopped already, but be defensive | 414 | #ifdef Q_OS_MAC |
| 407 | stop(); | 415 | // On mac, don't call QCoreApplication::processEvents() here. This is to prevent |
| 416 | // [NSApplication terminate:] from prematurely destroying the static destructors | ||
| 417 | // while we are waiting for the scripts to shutdown. We will pump the message | ||
| 418 | // queue later in the Application destructor. | ||
| 419 | if (workerThread->isRunning()) { | ||
| 420 | workerThread->quit(); | ||
| 421 | |||
| 422 | if (isEvaluating()) { | ||
| 423 | qCWarning(scriptengine) << "Script Engine has been running too long, aborting:" << getFilename(); | ||
| 424 | abortEvaluation(); | ||
| 425 | } | ||
| 408 | 426 | ||
| 427 | // Wait for the scripting thread to stop running, as | ||
| 428 | // flooding it with aborts/exceptions will persist it longer | ||
| 429 | static const auto MAX_SCRIPT_QUITTING_TIME = 0.5 * MSECS_PER_SECOND; | ||
| 430 | if (!workerThread->wait(MAX_SCRIPT_QUITTING_TIME)) { | ||
| 431 | workerThread->terminate(); | ||
| 432 | } | ||
| 433 | } | ||
| 434 | #else | ||
| 409 | auto startedWaiting = usecTimestampNow(); | 435 | auto startedWaiting = usecTimestampNow(); |
| 410 | while (workerThread->isRunning()) { | 436 | while (workerThread->isRunning()) { |
| 411 | // If the final evaluation takes too long, then tell the script engine to stop running | 437 | // If the final evaluation takes too long, then tell the script engine to stop running |
| @@ -443,6 +469,7 @@ void ScriptEngine::waitTillDoneRunning() { · 31 unmodified lines | |||
| 443 | // Avoid a pure busy wait | 469 | // Avoid a pure busy wait |
| 444 | QThread::yieldCurrentThread(); | 470 | QThread::yieldCurrentThread(); |
| 445 | } | 471 | } |
| 472 | #endif | ||
| 446 | 473 | ||
| 447 | scriptInfoMessage("Script Engine has stopped:" + getFilename()); | 474 | scriptInfoMessage("Script Engine has stopped:" + getFilename()); |
| 448 | } | 475 | } |
| @@ -992,6 +1019,31 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 543 unmodified lines | |||
| 992 | }; | 1019 | }; |
| 993 | }; | 1020 | }; |
| 994 | 1021 | ||
| 1022 | /**jsdoc | ||
| 1023 | * The name of an entity event. When the entity event occurs, any function that has been registered for that event via | ||
| 1024 | * {@link Script.addEventHandler} is called with parameters per the entity event. | ||
| 1025 | * <table> | ||
| 1026 | * <thead> | ||
| 1027 | * <tr><th>Event Name</th><th>Entity Event</th></tr> | ||
| 1028 | * </thead> | ||
| 1029 | * <tbody> | ||
| 1030 | * <tr><td><code>"enterEntity"</code></td><td>{@link Entities.enterEntity}</td></tr> | ||
| 1031 | * <tr><td><code>"leaveEntity"</code></td><td>{@link Entities.leaveEntity}</td></tr> | ||
| 1032 | * <tr><td><code>"mousePressOnEntity"</code></td><td>{@link Entities.mousePressOnEntity}</td></tr> | ||
| 1033 | * <tr><td><code>"mouseMoveOnEntity"</code></td><td>{@link Entities.mouseMoveOnEntity}</td></tr> | ||
| 1034 | * <tr><td><code>"mouseReleaseOnEntity"</code></td><td>{@link Entities.mouseReleaseOnEntity}</td></tr> | ||
| 1035 | * <tr><td><code>"clickDownOnEntity"</code></td><td>{@link Entities.clickDownOnEntity}</td></tr> | ||
| 1036 | * <tr><td><code>"holdingClickOnEntity"</code></td><td>{@link Entities.holdingClickOnEntity}</td></tr> | ||
| 1037 | * <tr><td><code>"clickReleaseOnEntity"</code></td><td>{@link Entities.clickReleaseOnEntity}</td></tr> | ||
| 1038 | * <tr><td><code>"hoverEnterEntity"</code></td><td>{@link Entities.hoverEnterEntity}</td></tr> | ||
| 1039 | * <tr><td><code>"hoverOverEntity"</code></td><td>{@link Entities.hoverOverEntity}</td></tr> | ||
| 1040 | * <tr><td><code>"hoverLeaveEntity"</code></td><td>{@link Entities.hoverLeaveEntity}</td></tr> | ||
| 1041 | * <tr><td><code>"collisionWithEntity"</code></td><td>{@link Entities.collisionWithEntity}</td></tr> | ||
| 1042 | * </tbody> | ||
| 1043 | * </table> | ||
| 1044 | * | ||
| 1045 | * @typedef {string} Script.EntityEvent | ||
| 1046 | */ | ||
| 995 | connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); | 1047 | connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); |
| 996 | connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); | 1048 | connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); |
| 997 | 1049 | ||
| @@ -1326,7 +1378,10 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM · 328 unmodified lines | |||
| 1326 | 1378 | ||
| 1327 | void ScriptEngine::updateMemoryCost(const qint64& deltaSize) { | 1379 | void ScriptEngine::updateMemoryCost(const qint64& deltaSize) { |
| 1328 | if (deltaSize > 0) { | 1380 | if (deltaSize > 0) { |
| 1381 | // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. | ||
| 1382 | #if defined(Q_OS_WIN) || defined(Q_OS_MAC) | ||
| 1329 | reportAdditionalMemoryCost(deltaSize); | 1383 | reportAdditionalMemoryCost(deltaSize); |
| 1384 | #endif | ||
| 1330 | } | 1385 | } |
| 1331 | } | 1386 | } |
| 1332 | 1387 | ||
| @@ -2152,7 +2207,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 819 unmodified lines | |||
| 2152 | } | 2207 | } |
| 2153 | 2208 | ||
| 2154 | /**jsdoc | 2209 | /**jsdoc |
| 2155 | * Triggered when the script starts for a user. | 2210 | * Triggered when the script starts for a user. See also, {@link Script.entityScriptPreloadFinished}. |
| 2156 | * <p>Note: Can only be connected to via <code>this.preload = function (...) { ... }</code> in the entity script.</p> | 2211 | * <p>Note: Can only be connected to via <code>this.preload = function (...) { ... }</code> in the entity script.</p> |
| 2157 | * <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table> | 2212 | * <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table> |
| 2158 | * @function Entities.preload | 2213 | * @function Entities.preload |
| @@ -2166,7 +2221,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 7 unmodified lines | |||
| 2166 | * this.entityID = entityID; | 2221 | * this.entityID = entityID; |
| 2167 | * print("Entity ID: " + this.entityID); | 2222 | * print("Entity ID: " + this.entityID); |
| 2168 | * }; | 2223 | * }; |
| 2169 | * ); | 2224 | * }); |
| 2170 | * | 2225 | * |
| 2171 | * var entityID = Entities.addEntity({ | 2226 | * var entityID = Entities.addEntity({ |
| 2172 | * type: "Box", | 2227 | * type: "Box", |
| @@ -2177,6 +2232,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 4 unmodified lines | |||
| 2177 | * lifetime: 300 // Delete after 5 minutes. | 2232 | * lifetime: 300 // Delete after 5 minutes. |
| 2178 | * }); | 2233 | * }); |
| 2179 | */ | 2234 | */ |
| 2235 | // The JSDoc is for the callEntityScriptMethod() call in this method. | ||
| 2180 | // since all of these operations can be asynch we will always do the actual work in the response handler | 2236 | // since all of these operations can be asynch we will always do the actual work in the response handler |
| 2181 | // for the download | 2237 | // for the download |
| 2182 | void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success , const QString& status) { | 2238 | void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success , const QString& status) { |
| @@ -2406,8 +2462,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 223 unmodified lines | |||
| 2406 | * <p>Note: Can only be connected to via <code>this.unoad = function () { ... }</code> in the entity script.</p> | 2462 | * <p>Note: Can only be connected to via <code>this.unoad = function () { ... }</code> in the entity script.</p> |
| 2407 | * <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table> | 2463 | * <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table> |
| 2408 | * @function Entities.unload | 2464 | * @function Entities.unload |
| 2465 | * @param {Uuid} entityID - The ID of the entity that the script is running in. | ||
| 2409 | * @returns {Signal} | 2466 | * @returns {Signal} |
| 2410 | */ | 2467 | */ |
| 2468 | // The JSDoc is for the callEntityScriptMethod() call in this method. | ||
| 2411 | void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) { | 2469 | void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) { |
| 2412 | if (QThread::currentThread() != thread()) { | 2470 | if (QThread::currentThread() != thread()) { |
| 2413 | #ifdef THREAD_DEBUGGING | 2471 | #ifdef THREAD_DEBUGGING |