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 | 224 | if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { |
| 225 | 225 | QObject::connect(this, &ScriptEngine::update, this, [this]() { |
| 226 | 226 | // process pending entity script content |
| 227 | − if (!_contentAvailableQueue.empty()) { | |
| 227 | + if (!_contentAvailableQueue.empty() && !(_isFinished || _isStopping)) { | |
| 228 | 228 | EntityScriptContentAvailableMap pending; |
| 229 | 229 | std::swap(_contentAvailableQueue, pending); |
| 230 | 230 | for (auto& pair : pending) { |
| @@ -343,7 +343,7 @@ void ScriptEngine::runDebuggable() { · 112 unmodified lines | ||
| 343 | 343 | // we check for 'now' in the past in case people set their clock back |
| 344 | 344 | if (_lastUpdate < now) { |
| 345 | 345 | float deltaTime = (float)(now - _lastUpdate) / (float)USECS_PER_SECOND; |
| 346 | − if (!_isFinished) { | |
| 346 | + if (!(_isFinished || _isStopping)) { | |
| 347 | 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 | 399 | void ScriptEngine::waitTillDoneRunning() { |
| 400 | + // Engine should be stopped already, but be defensive | |
| 401 | + stop(); | |
| 402 | + | |
| 400 | 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 | 410 | if (_isThreaded && workerThread) { |
| 403 | 411 | // We should never be waiting (blocking) on our own thread |
| 404 | 412 | assert(workerThread != QThread::currentThread()); |
| 405 | 413 | |
| 406 | − // Engine should be stopped already, but be defensive | |
| 407 | − stop(); | |
| 414 | +#ifdef Q_OS_MAC | |
| 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 | 435 | auto startedWaiting = usecTimestampNow(); |
| 410 | 436 | while (workerThread->isRunning()) { |
| 411 | 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 | 469 | // Avoid a pure busy wait |
| 444 | 470 | QThread::yieldCurrentThread(); |
| 445 | 471 | } |
| 472 | +#endif | |
| 446 | 473 | |
| 447 | 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 | 1047 | connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); |
| 996 | 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 | 1379 | void ScriptEngine::updateMemoryCost(const qint64& deltaSize) { |
| 1328 | 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 | 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 | 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 | 2211 | * <p>Note: Can only be connected to via <code>this.preload = function (...) { ... }</code> in the entity script.</p> |
| 2157 | 2212 | * <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table> |
| 2158 | 2213 | * @function Entities.preload |
| @@ -2166,7 +2221,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 7 unmodified lines | ||
| 2166 | 2221 | * this.entityID = entityID; |
| 2167 | 2222 | * print("Entity ID: " + this.entityID); |
| 2168 | 2223 | * }; |
| 2169 | − * ); | |
| 2224 | + * }); | |
| 2170 | 2225 | * |
| 2171 | 2226 | * var entityID = Entities.addEntity({ |
| 2172 | 2227 | * type: "Box", |
| @@ -2177,6 +2232,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 4 unmodified lines | ||
| 2177 | 2232 | * lifetime: 300 // Delete after 5 minutes. |
| 2178 | 2233 | * }); |
| 2179 | 2234 | */ |
| 2235 | +// The JSDoc is for the callEntityScriptMethod() call in this method. | |
| 2180 | 2236 | // since all of these operations can be asynch we will always do the actual work in the response handler |
| 2181 | 2237 | // for the download |
| 2182 | 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 | 2462 | * <p>Note: Can only be connected to via <code>this.unoad = function () { ... }</code> in the entity script.</p> |
| 2407 | 2463 | * <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table> |
| 2408 | 2464 | * @function Entities.unload |
| 2465 | + * @param {Uuid} entityID - The ID of the entity that the script is running in. | |
| 2409 | 2466 | * @returns {Signal} |
| 2410 | 2467 | */ |
| 2468 | +// The JSDoc is for the callEntityScriptMethod() call in this method. | |
| 2411 | 2469 | void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) { |
| 2412 | 2470 | if (QThread::currentThread() != thread()) { |
| 2413 | 2471 | #ifdef THREAD_DEBUGGING |