Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 95 files). Show all
Unified · Split
| @@ -148,25 +148,29 @@ static bool hasCorrectSyntax(const QScriptProgram& program, ScriptEngine* report · 147 unmodified lines | |||
| 148 | return true; | 148 | return true; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName, ScriptEngine* reportingEngine) { | 151 | static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName, ScriptEngine* reportingEngine, QString* exceptionMessage = nullptr) { |
| 152 | if (engine.hasUncaughtException()) { | 152 | if (engine.hasUncaughtException()) { |
| 153 | const auto backtrace = engine.uncaughtExceptionBacktrace(); | 153 | const auto backtrace = engine.uncaughtExceptionBacktrace(); |
| 154 | const auto exception = engine.uncaughtException().toString(); | 154 | const auto exception = engine.uncaughtException().toString(); |
| 155 | const auto line = QString::number(engine.uncaughtExceptionLineNumber()); | 155 | const auto line = QString::number(engine.uncaughtExceptionLineNumber()); |
| 156 | engine.clearExceptions(); | 156 | engine.clearExceptions(); |
| 157 | 157 | ||
| 158 | auto message = QString(SCRIPT_EXCEPTION_FORMAT).arg(exception, fileName, line); | 158 | QString message = QString(SCRIPT_EXCEPTION_FORMAT).arg(exception, fileName, line); |
| 159 | if (!backtrace.empty()) { | 159 | if (!backtrace.empty()) { |
| 160 | static const auto lineSeparator = "\n "; | 160 | static const auto lineSeparator = "\n "; |
| 161 | message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); | 161 | message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); |
| 162 | } | 162 | } |
| 163 | reportingEngine->scriptErrorMessage(qPrintable(message)); | 163 | reportingEngine->scriptErrorMessage(qPrintable(message)); |
| 164 | if (exceptionMessage) { | ||
| 165 | *exceptionMessage = message; | ||
| 166 | } | ||
| 164 | return true; | 167 | return true; |
| 165 | } | 168 | } |
| 166 | return false; | 169 | return false; |
| 167 | } | 170 | } |
| 168 | 171 | ||
| 169 | ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString) : | 172 | ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const QString& fileNameString) : |
| 173 | _context(context), | ||
| 170 | _scriptContents(scriptContents), | 174 | _scriptContents(scriptContents), |
| 171 | _timerFunctionMap(), | 175 | _timerFunctionMap(), |
| 172 | _fileNameString(fileNameString), | 176 | _fileNameString(fileNameString), |
| @@ -181,6 +185,22 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 8 unmodified lines | |||
| 181 | setProcessEventsInterval(MSECS_PER_SECOND); | 185 | setProcessEventsInterval(MSECS_PER_SECOND); |
| 182 | } | 186 | } |
| 183 | 187 | ||
| 188 | QString ScriptEngine::getContext() const { | ||
| 189 | switch (_context) { | ||
| 190 | case CLIENT_SCRIPT: | ||
| 191 | return "client"; | ||
| 192 | case ENTITY_CLIENT_SCRIPT: | ||
| 193 | return "entity_client"; | ||
| 194 | case ENTITY_SERVER_SCRIPT: | ||
| 195 | return "entity_server"; | ||
| 196 | case AGENT_SCRIPT: | ||
| 197 | return "agent"; | ||
| 198 | default: | ||
| 199 | return "unknown"; | ||
| 200 | } | ||
| 201 | return "unknown"; | ||
| 202 | } | ||
| 203 | |||
| 184 | ScriptEngine::~ScriptEngine() { | 204 | ScriptEngine::~ScriptEngine() { |
| 185 | scriptInfoMessage("Script Engine shutting down:" + getFilename()); | 205 | scriptInfoMessage("Script Engine shutting down:" + getFilename()); |
| 186 | 206 | ||
| @@ -563,11 +583,7 @@ void ScriptEngine::init() { · 376 unmodified lines | |||
| 563 | // constants | 583 | // constants |
| 564 | globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); | 584 | globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); |
| 565 | 585 | ||
| 566 | auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>(); | ||
| 567 | registerGlobalObject("Recording", recordingInterface.data()); | ||
| 568 | |||
| 569 | registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data()); | 586 | registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data()); |
| 570 | |||
| 571 | registerGlobalObject("Assets", &_assetScriptingInterface); | 587 | registerGlobalObject("Assets", &_assetScriptingInterface); |
| 572 | registerGlobalObject("Resources", DependencyManager::get<ResourceScriptingInterface>().data()); | 588 | registerGlobalObject("Resources", DependencyManager::get<ResourceScriptingInterface>().data()); |
| 573 | } | 589 | } |
| @@ -1377,6 +1393,15 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin · 803 unmodified lines | |||
| 1377 | } | 1393 | } |
| 1378 | } | 1394 | } |
| 1379 | 1395 | ||
| 1396 | bool ScriptEngine::getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const { | ||
| 1397 | auto it = _entityScripts.constFind(entityID); | ||
| 1398 | if (it == _entityScripts.constEnd()) { | ||
| 1399 | return false; | ||
| 1400 | } | ||
| 1401 | details = it.value(); | ||
| 1402 | return true; | ||
| 1403 | } | ||
| 1404 | |||
| 1380 | // since all of these operations can be asynch we will always do the actual work in the response handler | 1405 | // since all of these operations can be asynch we will always do the actual work in the response handler |
| 1381 | // for the download | 1406 | // for the download |
| 1382 | void ScriptEngine::loadEntityScript(QWeakPointer<ScriptEngine> theEngine, const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) { | 1407 | void ScriptEngine::loadEntityScript(QWeakPointer<ScriptEngine> theEngine, const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) { |
| @@ -1424,11 +1449,24 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 41 unmodified lines | |||
| 1424 | bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); | 1449 | bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); |
| 1425 | auto fileName = isURL ? scriptOrURL : "EmbeddedEntityScript"; | 1450 | auto fileName = isURL ? scriptOrURL : "EmbeddedEntityScript"; |
| 1426 | 1451 | ||
| 1452 | EntityScriptDetails newDetails; | ||
| 1453 | newDetails.scriptText = scriptOrURL; | ||
| 1454 | |||
| 1455 | if (!success) { | ||
| 1456 | newDetails.status = ERROR_LOADING_SCRIPT; | ||
| 1457 | newDetails.errorInfo = "Failed to load script"; | ||
| 1458 | _entityScripts[entityID] = newDetails; | ||
| 1459 | return; | ||
| 1460 | } | ||
| 1461 | |||
| 1427 | QScriptProgram program(contents, fileName); | 1462 | QScriptProgram program(contents, fileName); |
| 1428 | if (!hasCorrectSyntax(program, this)) { | 1463 | if (!hasCorrectSyntax(program, this)) { |
| 1429 | if (!isFileUrl) { | 1464 | if (!isFileUrl) { |
| 1430 | scriptCache->addScriptToBadScriptList(scriptOrURL); | 1465 | scriptCache->addScriptToBadScriptList(scriptOrURL); |
| 1431 | } | 1466 | } |
| 1467 | newDetails.status = ERROR_RUNNING_SCRIPT; | ||
| 1468 | newDetails.errorInfo = "Bad syntax"; | ||
| 1469 | _entityScripts[entityID] = newDetails; | ||
| 1432 | return; // done processing script | 1470 | return; // done processing script |
| 1433 | } | 1471 | } |
| 1434 | 1472 | ||
| @@ -1453,7 +1491,13 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 18 unmodified lines | |||
| 1453 | }); | 1491 | }); |
| 1454 | testConstructor = sandbox.evaluate(program); | 1492 | testConstructor = sandbox.evaluate(program); |
| 1455 | } | 1493 | } |
| 1456 | if (hadUncaughtExceptions(sandbox, program.fileName(), this)) { | 1494 | |
| 1495 | QString exceptionMessage; | ||
| 1496 | if (hadUncaughtExceptions(sandbox, program.fileName(), this, &exceptionMessage)) { | ||
| 1497 | newDetails.status = ERROR_RUNNING_SCRIPT; | ||
| 1498 | newDetails.errorInfo = exceptionMessage; | ||
| 1499 | _entityScripts[entityID] = newDetails; | ||
| 1500 | |||
| 1457 | return; | 1501 | return; |
| 1458 | } | 1502 | } |
| 1459 | 1503 | ||
| @@ -1476,6 +1520,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 16 unmodified lines | |||
| 1476 | scriptCache->addScriptToBadScriptList(scriptOrURL); | 1520 | scriptCache->addScriptToBadScriptList(scriptOrURL); |
| 1477 | } | 1521 | } |
| 1478 | 1522 | ||
| 1523 | newDetails.status = ERROR_RUNNING_SCRIPT; | ||
| 1524 | newDetails.errorInfo = "Could not find constructor"; | ||
| 1525 | _entityScripts[entityID] = newDetails; | ||
| 1526 | |||
| 1479 | return; // done processing script | 1527 | return; // done processing script |
| 1480 | } | 1528 | } |
| 1481 | 1529 | ||
| @@ -1492,8 +1540,11 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 10 unmodified lines | |||
| 1492 | }; | 1540 | }; |
| 1493 | doWithEnvironment(entityID, sandboxURL, initialization); | 1541 | doWithEnvironment(entityID, sandboxURL, initialization); |
| 1494 | 1542 | ||
| 1495 | EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified, sandboxURL }; | 1543 | newDetails.scriptObject = entityScriptObject; |
| 1544 | newDetails.lastModified = lastModified; | ||
| 1545 | newDetails.definingSandboxURL = sandboxURL; | ||
| 1496 | _entityScripts[entityID] = newDetails; | 1546 | _entityScripts[entityID] = newDetails; |
| 1547 | |||
| 1497 | if (isURL) { | 1548 | if (isURL) { |
| 1498 | setParentURL(""); | 1549 | setParentURL(""); |
| 1499 | } | 1550 | } |
| @@ -1519,7 +1570,9 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 19 unmodified lines | |||
| 1519 | #endif | 1570 | #endif |
| 1520 | 1571 | ||
| 1521 | if (_entityScripts.contains(entityID)) { | 1572 | if (_entityScripts.contains(entityID)) { |
| 1522 | callEntityScriptMethod(entityID, "unload"); | 1573 | if (_entityScripts[entityID].status == RUNNING) { |
| 1574 | callEntityScriptMethod(entityID, "unload"); | ||
| 1575 | } | ||
| 1523 | _entityScripts.remove(entityID); | 1576 | _entityScripts.remove(entityID); |
| 1524 | stopAllTimersForEntityScript(entityID); | 1577 | stopAllTimersForEntityScript(entityID); |
| 1525 | } | 1578 | } |
| @@ -1538,7 +1591,9 @@ void ScriptEngine::unloadAllEntityScripts() { · 12 unmodified lines | |||
| 1538 | qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; | 1591 | qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; |
| 1539 | #endif | 1592 | #endif |
| 1540 | foreach(const EntityItemID& entityID, _entityScripts.keys()) { | 1593 | foreach(const EntityItemID& entityID, _entityScripts.keys()) { |
| 1541 | callEntityScriptMethod(entityID, "unload"); | 1594 | if (_entityScripts[entityID].status == RUNNING) { |
| 1595 | callEntityScriptMethod(entityID, "unload"); | ||
| 1596 | } | ||
| 1542 | } | 1597 | } |
| 1543 | _entityScripts.clear(); | 1598 | _entityScripts.clear(); |
| 1544 | 1599 | ||
| @@ -1577,7 +1632,7 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 32 unmodified lines | |||
| 1577 | QString scriptContents = QTextStream(&file).readAll(); | 1632 | QString scriptContents = QTextStream(&file).readAll(); |
| 1578 | this->unloadEntityScript(entityID); | 1633 | this->unloadEntityScript(entityID); |
| 1579 | this->entityScriptContentAvailable(entityID, details.scriptText, scriptContents, true, true); | 1634 | this->entityScriptContentAvailable(entityID, details.scriptText, scriptContents, true, true); |
| 1580 | if (!_entityScripts.contains(entityID)) { | 1635 | if (!_entityScripts.contains(entityID) || _entityScripts[entityID].status != RUNNING) { |
| 1581 | scriptWarningMessage("Reload script " + details.scriptText + " failed"); | 1636 | scriptWarningMessage("Reload script " + details.scriptText + " failed"); |
| 1582 | } else { | 1637 | } else { |
| 1583 | details = _entityScripts[entityID]; | 1638 | details = _entityScripts[entityID]; |
| @@ -1636,7 +1691,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 52 unmodified lines | |||
| 1636 | #endif | 1691 | #endif |
| 1637 | 1692 | ||
| 1638 | refreshFileScript(entityID); | 1693 | refreshFileScript(entityID); |
| 1639 | if (_entityScripts.contains(entityID)) { | 1694 | if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) { |
| 1640 | EntityScriptDetails details = _entityScripts[entityID]; | 1695 | EntityScriptDetails details = _entityScripts[entityID]; |
| 1641 | QScriptValue entityScript = details.scriptObject; // previously loaded | 1696 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 1642 | if (entityScript.property(methodName).isFunction()) { | 1697 | if (entityScript.property(methodName).isFunction()) { |
| @@ -1668,7 +1723,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 25 unmodified lines | |||
| 1668 | #endif | 1723 | #endif |
| 1669 | 1724 | ||
| 1670 | refreshFileScript(entityID); | 1725 | refreshFileScript(entityID); |
| 1671 | if (_entityScripts.contains(entityID)) { | 1726 | if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) { |
| 1672 | EntityScriptDetails details = _entityScripts[entityID]; | 1727 | EntityScriptDetails details = _entityScripts[entityID]; |
| 1673 | QScriptValue entityScript = details.scriptObject; // previously loaded | 1728 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 1674 | if (entityScript.property(methodName).isFunction()) { | 1729 | if (entityScript.property(methodName).isFunction()) { |
| @@ -1701,7 +1756,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 26 unmodified lines | |||
| 1701 | #endif | 1756 | #endif |
| 1702 | 1757 | ||
| 1703 | refreshFileScript(entityID); | 1758 | refreshFileScript(entityID); |
| 1704 | if (_entityScripts.contains(entityID)) { | 1759 | if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) { |
| 1705 | EntityScriptDetails details = _entityScripts[entityID]; | 1760 | EntityScriptDetails details = _entityScripts[entityID]; |
| 1706 | QScriptValue entityScript = details.scriptObject; // previously loaded | 1761 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 1707 | if (entityScript.property(methodName).isFunction()) { | 1762 | if (entityScript.property(methodName).isFunction()) { |