Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 305 files). Show all
Unified · Split
| @@ -28,7 +28,9 @@ · 27 unmodified lines | |||
| 28 | #include <udt/PacketHeaders.h> | 28 | #include <udt/PacketHeaders.h> |
| 29 | #include <UUID.h> | 29 | #include <UUID.h> |
| 30 | 30 | ||
| 31 | #include "AnimationObject.h" | 31 | #include <controllers/ScriptingInterface.h> |
| 32 | #include <AnimationObject.h> | ||
| 33 | |||
| 32 | #include "ArrayBufferViewClass.h" | 34 | #include "ArrayBufferViewClass.h" |
| 33 | #include "BatchLoader.h" | 35 | #include "BatchLoader.h" |
| 34 | #include "DataViewClass.h" | 36 | #include "DataViewClass.h" |
| @@ -76,13 +78,16 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { · 41 unmodified lines | |||
| 76 | out = qobject_cast<AvatarData*>(object.toQObject()); | 78 | out = qobject_cast<AvatarData*>(object.toQObject()); |
| 77 | } | 79 | } |
| 78 | 80 | ||
| 79 | QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) { | 81 | QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) { |
| 80 | return engine->newQObject(in); | 82 | return engine->newQObject(in); |
| 81 | } | 83 | } |
| 82 | void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) { | 84 | |
| 83 | out = qobject_cast<AbstractInputController*>(object.toQObject()); | 85 | void inputControllerFromScriptValue(const QScriptValue &object, controller::InputController* &out) { |
| 86 | out = qobject_cast<controller::InputController*>(object.toQObject()); | ||
| 84 | } | 87 | } |
| 85 | 88 | ||
| 89 | |||
| 90 | |||
| 86 | static bool hasCorrectSyntax(const QScriptProgram& program) { | 91 | static bool hasCorrectSyntax(const QScriptProgram& program) { |
| 87 | const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); | 92 | const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); |
| 88 | if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { | 93 | if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { |
| @@ -114,20 +119,17 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName · 25 unmodified lines | |||
| 114 | return false; | 119 | return false; |
| 115 | } | 120 | } |
| 116 | 121 | ||
| 117 | ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, | 122 | ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) : |
| 118 | AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) : | 123 | _scriptContents(scriptContents), |
| 119 | 124 | _isFinished(false), | |
| 120 | _scriptContents(scriptContents), | 125 | _isRunning(false), |
| 121 | _isFinished(false), | 126 | _isInitialized(false), |
| 122 | _isRunning(false), | 127 | _timerFunctionMap(), |
| 123 | _isInitialized(false), | 128 | _wantSignals(wantSignals), |
| 124 | _timerFunctionMap(), | 129 | _fileNameString(fileNameString), |
| 125 | _wantSignals(wantSignals), | 130 | _isUserLoaded(false), |
| 126 | _controllerScriptingInterface(controllerScriptingInterface), | 131 | _isReloading(false), |
| 127 | _fileNameString(fileNameString), | 132 | _arrayBufferClass(new ArrayBufferClass(this)) |
| 128 | _isUserLoaded(false), | ||
| 129 | _isReloading(false), | ||
| 130 | _arrayBufferClass(new ArrayBufferClass(this)) | ||
| 131 | { | 133 | { |
| 132 | _allScriptsMutex.lock(); | 134 | _allScriptsMutex.lock(); |
| 133 | _allKnownScriptEngines.insert(this); | 135 | _allKnownScriptEngines.insert(this); |
| @@ -285,6 +287,27 @@ void ScriptEngine::errorInLoadingScript(const QUrl& url) { · 151 unmodified lines | |||
| 285 | } | 287 | } |
| 286 | } | 288 | } |
| 287 | 289 | ||
| 290 | // Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of | ||
| 291 | // callAnimationStateHandler requires that the type be registered. | ||
| 292 | // These two are meaningful, if we ever do want to use them... | ||
| 293 | static QScriptValue animVarMapToScriptValue(QScriptEngine* engine, const AnimVariantMap& parameters) { | ||
| 294 | QStringList unused; | ||
| 295 | return parameters.animVariantMapToScriptValue(engine, unused, false); | ||
| 296 | } | ||
| 297 | static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap& parameters) { | ||
| 298 | parameters.animVariantMapFromScriptValue(value); | ||
| 299 | } | ||
| 300 | // ... while these two are not. But none of the four are ever used. | ||
| 301 | static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine, const AnimVariantResultHandler& resultHandler) { | ||
| 302 | qCCritical(scriptengine) << "Attempt to marshall result handler to javascript"; | ||
| 303 | assert(false); | ||
| 304 | return QScriptValue(); | ||
| 305 | } | ||
| 306 | static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantResultHandler& resultHandler) { | ||
| 307 | qCCritical(scriptengine) << "Attempt to marshall result handler from javascript"; | ||
| 308 | assert(false); | ||
| 309 | } | ||
| 310 | |||
| 288 | void ScriptEngine::init() { | 311 | void ScriptEngine::init() { |
| 289 | if (_isInitialized) { | 312 | if (_isInitialized) { |
| 290 | return; // only initialize once | 313 | return; // only initialize once |
| @@ -337,27 +360,26 @@ void ScriptEngine::init() { · 46 unmodified lines | |||
| 337 | 360 | ||
| 338 | registerGlobalObject("Script", this); | 361 | registerGlobalObject("Script", this); |
| 339 | registerGlobalObject("Audio", &AudioScriptingInterface::getInstance()); | 362 | registerGlobalObject("Audio", &AudioScriptingInterface::getInstance()); |
| 340 | registerGlobalObject("Controller", _controllerScriptingInterface); | ||
| 341 | registerGlobalObject("Entities", entityScriptingInterface.data()); | 363 | registerGlobalObject("Entities", entityScriptingInterface.data()); |
| 342 | registerGlobalObject("Quat", &_quatLibrary); | 364 | registerGlobalObject("Quat", &_quatLibrary); |
| 343 | registerGlobalObject("Vec3", &_vec3Library); | 365 | registerGlobalObject("Vec3", &_vec3Library); |
| 344 | registerGlobalObject("Uuid", &_uuidLibrary); | 366 | registerGlobalObject("Uuid", &_uuidLibrary); |
| 345 | registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data()); | 367 | registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data()); |
| 346 | 368 | qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue); | |
| 369 | qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue); | ||
| 370 | |||
| 347 | // constants | 371 | // constants |
| 348 | globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); | 372 | globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); |
| 349 | 373 | ||
| 350 | if (_controllerScriptingInterface) { | 374 | auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>(); |
| 351 | _controllerScriptingInterface->registerControllerTypes(this); | 375 | registerGlobalObject("Controller", scriptingInterface.data()); |
| 352 | } | 376 | UserInputMapper::registerControllerTypes(this); |
| 353 | |||
| 354 | |||
| 355 | } | 377 | } |
| 356 | 378 | ||
| 357 | void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { | 379 | void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { |
| 358 | if (QThread::currentThread() != thread()) { | 380 | if (QThread::currentThread() != thread()) { |
| 359 | #ifdef THREAD_DEBUGGING | 381 | #ifdef THREAD_DEBUGGING |
| 360 | qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | 382 | qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; |
| 361 | #endif | 383 | #endif |
| 362 | QMetaObject::invokeMethod(this, "registerValue", | 384 | QMetaObject::invokeMethod(this, "registerValue", |
| 363 | Q_ARG(const QString&, valueName), | 385 | Q_ARG(const QString&, valueName), |
| @@ -558,7 +580,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 194 unmodified lines | |||
| 558 | auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { | 580 | auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { |
| 559 | return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { | 581 | return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { |
| 560 | forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), | 582 | forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), |
| 561 | collisionToScriptValue(this, collision) }); | 583 | collisionToScriptValue(this, collision) }); |
| 562 | }; | 584 | }; |
| 563 | }; | 585 | }; |
| 564 | 586 | ||
| @@ -743,6 +765,27 @@ void ScriptEngine::stop() { · 178 unmodified lines | |||
| 743 | } | 765 | } |
| 744 | } | 766 | } |
| 745 | 767 | ||
| 768 | // Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread. | ||
| 769 | void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) { | ||
| 770 | if (QThread::currentThread() != thread()) { | ||
| 771 | #ifdef THREAD_DEBUGGING | ||
| 772 | qDebug() << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | ||
| 773 | #endif | ||
| 774 | QMetaObject::invokeMethod(this, "callAnimationStateHandler", | ||
| 775 | Q_ARG(QScriptValue, callback), | ||
| 776 | Q_ARG(AnimVariantMap, parameters), | ||
| 777 | Q_ARG(QStringList, names), | ||
| 778 | Q_ARG(bool, useNames), | ||
| 779 | Q_ARG(AnimVariantResultHandler, resultHandler)); | ||
| 780 | return; | ||
| 781 | } | ||
| 782 | QScriptValue javascriptParameters = parameters.animVariantMapToScriptValue(this, names, useNames); | ||
| 783 | QScriptValueList callingArguments; | ||
| 784 | callingArguments << javascriptParameters; | ||
| 785 | QScriptValue result = callback.call(QScriptValue(), callingArguments); | ||
| 786 | resultHandler(result); | ||
| 787 | } | ||
| 788 | |||
| 746 | void ScriptEngine::timerFired() { | 789 | void ScriptEngine::timerFired() { |
| 747 | QTimer* callingTimer = reinterpret_cast<QTimer*>(sender()); | 790 | QTimer* callingTimer = reinterpret_cast<QTimer*>(sender()); |
| 748 | QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); | 791 | QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); |
| @@ -928,9 +971,8 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin · 179 unmodified lines | |||
| 928 | if (QThread::currentThread() != thread()) { | 971 | if (QThread::currentThread() != thread()) { |
| 929 | qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; | 972 | qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; |
| 930 | assert(false); | 973 | assert(false); |
| 931 | return; | 974 | return ; |
| 932 | } | 975 | } |
| 933 | |||
| 934 | if (!_registeredHandlers.contains(entityID)) { | 976 | if (!_registeredHandlers.contains(entityID)) { |
| 935 | return; | 977 | return; |
| 936 | } | 978 | } |