Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 266 files). Show all
Unified · Split
| @@ -721,6 +721,7 @@ void ScriptEngine::init() { · 720 unmodified lines | ||
| 721 | 721 | registerGlobalObject("Midi", DependencyManager::get<Midi>().data()); |
| 722 | 722 | |
| 723 | 723 | registerGlobalObject("Entities", entityScriptingInterface.data()); |
| 724 | + registerFunction("Entities", "getMultipleEntityProperties", EntityScriptingInterface::getMultipleEntityProperties); | |
| 724 | 725 | registerGlobalObject("Quat", &_quatLibrary); |
| 725 | 726 | registerGlobalObject("Vec3", &_vec3Library); |
| 726 | 727 | registerGlobalObject("Mat4", &_mat4Library); |
| @@ -1974,8 +1975,9 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin · 1247 unmodified lines | ||
| 1974 | 1975 | } |
| 1975 | 1976 | |
| 1976 | 1977 | int ScriptEngine::getNumRunningEntityScripts() const { |
| 1978 | + QReadLocker locker { &_entityScriptsLock }; | |
| 1977 | 1979 | int sum = 0; |
| 1978 | − for (auto& st : _entityScripts) { | |
| 1980 | + for (const auto& st : _entityScripts) { | |
| 1979 | 1981 | if (st.status == EntityScriptStatus::RUNNING) { |
| 1980 | 1982 | ++sum; |
| 1981 | 1983 | } |
| @@ -1984,14 +1986,20 @@ int ScriptEngine::getNumRunningEntityScripts() const { · 2 unmodified lines | ||
| 1984 | 1986 | } |
| 1985 | 1987 | |
| 1986 | 1988 | void ScriptEngine::setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details) { |
| 1987 | − _entityScripts[entityID] = details; | |
| 1989 | + { | |
| 1990 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 1991 | + _entityScripts[entityID] = details; | |
| 1992 | + } | |
| 1988 | 1993 | emit entityScriptDetailsUpdated(); |
| 1989 | 1994 | } |
| 1990 | 1995 | |
| 1991 | 1996 | void ScriptEngine::updateEntityScriptStatus(const EntityItemID& entityID, const EntityScriptStatus &status, const QString& errorInfo) { |
| 1992 | − EntityScriptDetails &details = _entityScripts[entityID]; | |
| 1993 | − details.status = status; | |
| 1994 | − details.errorInfo = errorInfo; | |
| 1997 | + { | |
| 1998 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 1999 | + EntityScriptDetails& details = _entityScripts[entityID]; | |
| 2000 | + details.status = status; | |
| 2001 | + details.errorInfo = errorInfo; | |
| 2002 | + } | |
| 1995 | 2003 | emit entityScriptDetailsUpdated(); |
| 1996 | 2004 | } |
| 1997 | 2005 | |
| @@ -2042,6 +2050,7 @@ QFuture<QVariant> ScriptEngine::getLocalEntityScriptDetails(const EntityItemID& · 44 unmodified lines | ||
| 2042 | 2050 | } |
| 2043 | 2051 | |
| 2044 | 2052 | bool ScriptEngine::getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const { |
| 2053 | + QReadLocker locker { &_entityScriptsLock }; | |
| 2045 | 2054 | auto it = _entityScripts.constFind(entityID); |
| 2046 | 2055 | if (it == _entityScripts.constEnd()) { |
| 2047 | 2056 | return false; |
| @@ -2050,6 +2059,11 @@ bool ScriptEngine::getEntityScriptDetails(const EntityItemID& entityID, EntitySc · 2 unmodified lines | ||
| 2050 | 2059 | return true; |
| 2051 | 2060 | } |
| 2052 | 2061 | |
| 2062 | +bool ScriptEngine::hasEntityScriptDetails(const EntityItemID& entityID) const { | |
| 2063 | + QReadLocker locker { &_entityScriptsLock }; | |
| 2064 | + return _entityScripts.contains(entityID); | |
| 2065 | +} | |
| 2066 | + | |
| 2053 | 2067 | const static EntityItemID BAD_SCRIPT_UUID_PLACEHOLDER { "{20170224-dead-face-0000-cee000021114}" }; |
| 2054 | 2068 | |
| 2055 | 2069 | void ScriptEngine::processDeferredEntityLoads(const QString& entityScript, const EntityItemID& leaderID) { |
| @@ -2064,14 +2078,15 @@ void ScriptEngine::processDeferredEntityLoads(const QString& entityScript, const · 8 unmodified lines | ||
| 2064 | 2078 | } |
| 2065 | 2079 | foreach(DeferredLoadEntity retry, retryLoads) { |
| 2066 | 2080 | // check whether entity was since been deleted |
| 2067 | − if (!_entityScripts.contains(retry.entityID)) { | |
| 2081 | + | |
| 2082 | + EntityScriptDetails details; | |
| 2083 | + if (!getEntityScriptDetails(retry.entityID, details)) { | |
| 2068 | 2084 | qCDebug(scriptengine) << "processDeferredEntityLoads -- entity details gone (entity deleted?)" |
| 2069 | 2085 | << retry.entityID; |
| 2070 | 2086 | continue; |
| 2071 | 2087 | } |
| 2072 | 2088 | |
| 2073 | 2089 | // check whether entity has since been unloaded or otherwise errored-out |
| 2074 | − auto details = _entityScripts[retry.entityID]; | |
| 2075 | 2090 | if (details.status != EntityScriptStatus::PENDING) { |
| 2076 | 2091 | qCDebug(scriptengine) << "processDeferredEntityLoads -- entity status no longer PENDING; " |
| 2077 | 2092 | << retry.entityID << details.status; |
| @@ -2079,7 +2094,11 @@ void ScriptEngine::processDeferredEntityLoads(const QString& entityScript, const · 1 unmodified line | ||
| 2079 | 2094 | } |
| 2080 | 2095 | |
| 2081 | 2096 | // propagate leader's failure reasons to the pending entity |
| 2082 | − const auto leaderDetails = _entityScripts[leaderID]; | |
| 2097 | + EntityScriptDetails leaderDetails; | |
| 2098 | + { | |
| 2099 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2100 | + leaderDetails = _entityScripts[leaderID]; | |
| 2101 | + } | |
| 2083 | 2102 | if (leaderDetails.status != EntityScriptStatus::RUNNING) { |
| 2084 | 2103 | qCDebug(scriptengine) << QString("... pending load of %1 cancelled (leader: %2 status: %3)") |
| 2085 | 2104 | .arg(retry.entityID.toString()).arg(leaderID.toString()).arg(leaderDetails.status); |
| @@ -2125,7 +2144,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 39 unmodified lines | ||
| 2125 | 2144 | return; |
| 2126 | 2145 | } |
| 2127 | 2146 | |
| 2128 | − if (!_entityScripts.contains(entityID)) { | |
| 2147 | + if (!hasEntityScriptDetails(entityID)) { | |
| 2129 | 2148 | // make sure EntityScriptDetails has an entry for this UUID right away |
| 2130 | 2149 | // (which allows bailing from the loading/provisioning process early if the Entity gets deleted mid-flight) |
| 2131 | 2150 | updateEntityScriptStatus(entityID, EntityScriptStatus::PENDING, "...pending..."); |
| @@ -2166,9 +2185,12 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 34 unmodified lines | ||
| 2166 | 2185 | _occupiedScriptURLs[entityScript] = entityID; |
| 2167 | 2186 | |
| 2168 | 2187 | #ifdef DEBUG_ENTITY_STATES |
| 2169 | − auto previousStatus = _entityScripts.contains(entityID) ? _entityScripts[entityID].status : EntityScriptStatus::PENDING; | |
| 2170 | − qCDebug(scriptengine) << "loadEntityScript.LOADING: " << entityScript << entityID.toString() | |
| 2171 | − << "(previous: " << previousStatus << ")"; | |
| 2188 | + { | |
| 2189 | + EntityScriptDetails details; | |
| 2190 | + bool hasEntityScript = getEntityScriptDetails(entityID, details); | |
| 2191 | + qCDebug(scriptengine) << "loadEntityScript.LOADING: " << entityScript << entityID.toString() | |
| 2192 | + << "(previous: " << (hasEntityScript ? details.status : EntityScriptStatus::PENDING) << ")"; | |
| 2193 | + } | |
| 2172 | 2194 | #endif |
| 2173 | 2195 | |
| 2174 | 2196 | EntityScriptDetails newDetails; |
| @@ -2197,7 +2219,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 22 unmodified lines | ||
| 2197 | 2219 | #ifdef DEBUG_ENTITY_STATES |
| 2198 | 2220 | qCDebug(scriptengine) << "loadEntityScript.contentAvailable" << status << QUrl(url).fileName() << entityID.toString(); |
| 2199 | 2221 | #endif |
| 2200 | − if (!isStopping() && _entityScripts.contains(entityID)) { | |
| 2222 | + if (!isStopping() && hasEntityScriptDetails(entityID)) { | |
| 2201 | 2223 | _contentAvailableQueue[entityID] = { entityID, url, contents, isURL, success, status }; |
| 2202 | 2224 | } else { |
| 2203 | 2225 | #ifdef DEBUG_ENTITY_STATES |
| @@ -2267,8 +2289,11 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 63 unmodified lines | ||
| 2267 | 2289 | bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); |
| 2268 | 2290 | auto fileName = isURL ? scriptOrURL : "about:EmbeddedEntityScript"; |
| 2269 | 2291 | |
| 2270 | − const EntityScriptDetails &oldDetails = _entityScripts[entityID]; | |
| 2271 | − const QString entityScript = oldDetails.scriptText; | |
| 2292 | + QString entityScript; | |
| 2293 | + { | |
| 2294 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2295 | + entityScript = _entityScripts[entityID].scriptText; | |
| 2296 | + } | |
| 2272 | 2297 | |
| 2273 | 2298 | EntityScriptDetails newDetails; |
| 2274 | 2299 | newDetails.scriptText = scriptOrURL; |
| @@ -2418,6 +2443,8 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 143 unmodified lines | ||
| 2418 | 2443 | // if we got this far, then call the preload method |
| 2419 | 2444 | callEntityScriptMethod(entityID, "preload"); |
| 2420 | 2445 | |
| 2446 | + emit entityScriptPreloadFinished(entityID); | |
| 2447 | + | |
| 2421 | 2448 | _occupiedScriptURLs.remove(entityScript); |
| 2422 | 2449 | processDeferredEntityLoads(entityScript, entityID); |
| 2423 | 2450 | } |
| @@ -2446,8 +2473,8 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR · 22 unmodified lines | ||
| 2446 | 2473 | "entityID:" << entityID; |
| 2447 | 2474 | #endif |
| 2448 | 2475 | |
| 2449 | − if (_entityScripts.contains(entityID)) { | |
| 2450 | − const EntityScriptDetails &oldDetails = _entityScripts[entityID]; | |
| 2476 | + EntityScriptDetails oldDetails; | |
| 2477 | + if (getEntityScriptDetails(entityID, oldDetails)) { | |
| 2451 | 2478 | auto scriptText = oldDetails.scriptText; |
| 2452 | 2479 | |
| 2453 | 2480 | if (isEntityScriptRunning(entityID)) { |
| @@ -2460,7 +2487,10 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR · 6 unmodified lines | ||
| 2460 | 2487 | #endif |
| 2461 | 2488 | if (shouldRemoveFromMap) { |
| 2462 | 2489 | // this was a deleted entity, we've been asked to remove it from the map |
| 2463 | − _entityScripts.remove(entityID); | |
| 2490 | + { | |
| 2491 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2492 | + _entityScripts.remove(entityID); | |
| 2493 | + } | |
| 2464 | 2494 | emit entityScriptDetailsUpdated(); |
| 2465 | 2495 | } else if (oldDetails.status != EntityScriptStatus::UNLOADED) { |
| 2466 | 2496 | EntityScriptDetails newDetails; |
| @@ -2491,10 +2521,19 @@ void ScriptEngine::unloadAllEntityScripts() { · 24 unmodified lines | ||
| 2491 | 2521 | #ifdef THREAD_DEBUGGING |
| 2492 | 2522 | qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; |
| 2493 | 2523 | #endif |
| 2494 | − foreach(const EntityItemID& entityID, _entityScripts.keys()) { | |
| 2524 | + | |
| 2525 | + QList<EntityItemID> keys; | |
| 2526 | + { | |
| 2527 | + QReadLocker locker{ &_entityScriptsLock }; | |
| 2528 | + keys = _entityScripts.keys(); | |
| 2529 | + } | |
| 2530 | + foreach(const EntityItemID& entityID, keys) { | |
| 2495 | 2531 | unloadEntityScript(entityID); |
| 2496 | 2532 | } |
| 2497 | − _entityScripts.clear(); | |
| 2533 | + { | |
| 2534 | + QWriteLocker locker{ &_entityScriptsLock }; | |
| 2535 | + _entityScripts.clear(); | |
| 2536 | + } | |
| 2498 | 2537 | emit entityScriptDetailsUpdated(); |
| 2499 | 2538 | _occupiedScriptURLs.clear(); |
| 2500 | 2539 | |
| @@ -2508,7 +2547,7 @@ void ScriptEngine::unloadAllEntityScripts() { · 7 unmodified lines | ||
| 2508 | 2547 | } |
| 2509 | 2548 | |
| 2510 | 2549 | void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { |
| 2511 | − if (!HIFI_AUTOREFRESH_FILE_SCRIPTS || !_entityScripts.contains(entityID)) { | |
| 2550 | + if (!HIFI_AUTOREFRESH_FILE_SCRIPTS || !hasEntityScriptDetails(entityID)) { | |
| 2512 | 2551 | return; |
| 2513 | 2552 | } |
| 2514 | 2553 | |
| @@ -2518,7 +2557,11 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 3 unmodified lines | ||
| 2518 | 2557 | } |
| 2519 | 2558 | recurseGuard = true; |
| 2520 | 2559 | |
| 2521 | − EntityScriptDetails details = _entityScripts[entityID]; | |
| 2560 | + EntityScriptDetails details; | |
| 2561 | + { | |
| 2562 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2563 | + details = _entityScripts[entityID]; | |
| 2564 | + } | |
| 2522 | 2565 | // Check to see if a file based script needs to be reloaded (easier debugging) |
| 2523 | 2566 | if (details.lastModified > 0) { |
| 2524 | 2567 | QString filePath = QUrl(details.scriptText).toLocalFile(); |
| @@ -2584,7 +2627,11 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 59 unmodified lines | ||
| 2584 | 2627 | refreshFileScript(entityID); |
| 2585 | 2628 | } |
| 2586 | 2629 | if (isEntityScriptRunning(entityID)) { |
| 2587 | − EntityScriptDetails details = _entityScripts[entityID]; | |
| 2630 | + EntityScriptDetails details; | |
| 2631 | + { | |
| 2632 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2633 | + details = _entityScripts[entityID]; | |
| 2634 | + } | |
| 2588 | 2635 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 2589 | 2636 | |
| 2590 | 2637 | // If this is a remote call, we need to check to see if the function is remotely callable |
| @@ -2646,7 +2693,11 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 55 unmodified lines | ||
| 2646 | 2693 | refreshFileScript(entityID); |
| 2647 | 2694 | } |
| 2648 | 2695 | if (isEntityScriptRunning(entityID)) { |
| 2649 | − EntityScriptDetails details = _entityScripts[entityID]; | |
| 2696 | + EntityScriptDetails details; | |
| 2697 | + { | |
| 2698 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2699 | + details = _entityScripts[entityID]; | |
| 2700 | + } | |
| 2650 | 2701 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 2651 | 2702 | if (entityScript.property(methodName).isFunction()) { |
| 2652 | 2703 | QScriptValueList args; |
| @@ -2680,7 +2731,11 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 27 unmodified lines | ||
| 2680 | 2731 | refreshFileScript(entityID); |
| 2681 | 2732 | } |
| 2682 | 2733 | if (isEntityScriptRunning(entityID)) { |
| 2683 | − EntityScriptDetails details = _entityScripts[entityID]; | |
| 2734 | + EntityScriptDetails details; | |
| 2735 | + { | |
| 2736 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2737 | + details = _entityScripts[entityID]; | |
| 2738 | + } | |
| 2684 | 2739 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 2685 | 2740 | if (entityScript.property(methodName).isFunction()) { |
| 2686 | 2741 | QScriptValueList args; |