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