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 | 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 | 152 | if (engine.hasUncaughtException()) { |
| 153 | 153 | const auto backtrace = engine.uncaughtExceptionBacktrace(); |
| 154 | 154 | const auto exception = engine.uncaughtException().toString(); |
| 155 | 155 | const auto line = QString::number(engine.uncaughtExceptionLineNumber()); |
| 156 | 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 | 159 | if (!backtrace.empty()) { |
| 160 | 160 | static const auto lineSeparator = "\n "; |
| 161 | 161 | message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); |
| 162 | 162 | } |
| 163 | 163 | reportingEngine->scriptErrorMessage(qPrintable(message)); |
| 164 | + if (exceptionMessage) { | |
| 165 | + *exceptionMessage = message; | |
| 166 | + } | |
| 164 | 167 | return true; |
| 165 | 168 | } |
| 166 | 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 | 174 | _scriptContents(scriptContents), |
| 171 | 175 | _timerFunctionMap(), |
| 172 | 176 | _fileNameString(fileNameString), |
| @@ -181,6 +185,22 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 8 unmodified lines | ||
| 181 | 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 | 204 | ScriptEngine::~ScriptEngine() { |
| 185 | 205 | scriptInfoMessage("Script Engine shutting down:" + getFilename()); |
| 186 | 206 | |
| @@ -563,11 +583,7 @@ void ScriptEngine::init() { · 376 unmodified lines | ||
| 563 | 583 | // constants |
| 564 | 584 | globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); |
| 565 | 585 | |
| 566 | − auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>(); | |
| 567 | − registerGlobalObject("Recording", recordingInterface.data()); | |
| 568 | − | |
| 569 | 586 | registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data()); |
| 570 | − | |
| 571 | 587 | registerGlobalObject("Assets", &_assetScriptingInterface); |
| 572 | 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 | 1405 | // since all of these operations can be asynch we will always do the actual work in the response handler |
| 1381 | 1406 | // for the download |
| 1382 | 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 | 1449 | bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); |
| 1425 | 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 | 1462 | QScriptProgram program(contents, fileName); |
| 1428 | 1463 | if (!hasCorrectSyntax(program, this)) { |
| 1429 | 1464 | if (!isFileUrl) { |
| 1430 | 1465 | scriptCache->addScriptToBadScriptList(scriptOrURL); |
| 1431 | 1466 | } |
| 1467 | + newDetails.status = ERROR_RUNNING_SCRIPT; | |
| 1468 | + newDetails.errorInfo = "Bad syntax"; | |
| 1469 | + _entityScripts[entityID] = newDetails; | |
| 1432 | 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 | 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 | 1501 | return; |
| 1458 | 1502 | } |
| 1459 | 1503 | |
| @@ -1476,6 +1520,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 16 unmodified lines | ||
| 1476 | 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 | 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 | 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 | 1546 | _entityScripts[entityID] = newDetails; |
| 1547 | + | |
| 1497 | 1548 | if (isURL) { |
| 1498 | 1549 | setParentURL(""); |
| 1499 | 1550 | } |
| @@ -1519,7 +1570,9 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 19 unmodified lines | ||
| 1519 | 1570 | #endif |
| 1520 | 1571 | |
| 1521 | 1572 | if (_entityScripts.contains(entityID)) { |
| 1522 | − callEntityScriptMethod(entityID, "unload"); | |
| 1573 | + if (_entityScripts[entityID].status == RUNNING) { | |
| 1574 | + callEntityScriptMethod(entityID, "unload"); | |
| 1575 | + } | |
| 1523 | 1576 | _entityScripts.remove(entityID); |
| 1524 | 1577 | stopAllTimersForEntityScript(entityID); |
| 1525 | 1578 | } |
| @@ -1538,7 +1591,9 @@ void ScriptEngine::unloadAllEntityScripts() { · 12 unmodified lines | ||
| 1538 | 1591 | qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; |
| 1539 | 1592 | #endif |
| 1540 | 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 | 1598 | _entityScripts.clear(); |
| 1544 | 1599 | |
| @@ -1577,7 +1632,7 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 32 unmodified lines | ||
| 1577 | 1632 | QString scriptContents = QTextStream(&file).readAll(); |
| 1578 | 1633 | this->unloadEntityScript(entityID); |
| 1579 | 1634 | this->entityScriptContentAvailable(entityID, details.scriptText, scriptContents, true, true); |
| 1580 | − if (!_entityScripts.contains(entityID)) { | |
| 1635 | + if (!_entityScripts.contains(entityID) || _entityScripts[entityID].status != RUNNING) { | |
| 1581 | 1636 | scriptWarningMessage("Reload script " + details.scriptText + " failed"); |
| 1582 | 1637 | } else { |
| 1583 | 1638 | details = _entityScripts[entityID]; |
| @@ -1636,7 +1691,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 52 unmodified lines | ||
| 1636 | 1691 | #endif |
| 1637 | 1692 | |
| 1638 | 1693 | refreshFileScript(entityID); |
| 1639 | − if (_entityScripts.contains(entityID)) { | |
| 1694 | + if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) { | |
| 1640 | 1695 | EntityScriptDetails details = _entityScripts[entityID]; |
| 1641 | 1696 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 1642 | 1697 | if (entityScript.property(methodName).isFunction()) { |
| @@ -1668,7 +1723,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 25 unmodified lines | ||
| 1668 | 1723 | #endif |
| 1669 | 1724 | |
| 1670 | 1725 | refreshFileScript(entityID); |
| 1671 | − if (_entityScripts.contains(entityID)) { | |
| 1726 | + if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) { | |
| 1672 | 1727 | EntityScriptDetails details = _entityScripts[entityID]; |
| 1673 | 1728 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 1674 | 1729 | if (entityScript.property(methodName).isFunction()) { |
| @@ -1701,7 +1756,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 26 unmodified lines | ||
| 1701 | 1756 | #endif |
| 1702 | 1757 | |
| 1703 | 1758 | refreshFileScript(entityID); |
| 1704 | − if (_entityScripts.contains(entityID)) { | |
| 1759 | + if (_entityScripts.contains(entityID) && _entityScripts[entityID].status == RUNNING) { | |
| 1705 | 1760 | EntityScriptDetails details = _entityScripts[entityID]; |
| 1706 | 1761 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 1707 | 1762 | if (entityScript.property(methodName).isFunction()) { |