History

Call back to Javascript asynchronously, so that we don't block and the script's engine doesn't have thread conflicts.

Howard Stearns committed 11 years ago

Commit 9fd61901 parent 574a51e8 files · +80 −42Browse files

Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 8 files). Show all

Unified · Split

libraries/script-engine/src/ScriptEngine.cpp+34−3
@@ -258,6 +258,15 @@ void ScriptEngine::errorInLoadingScript(const QUrl& url) { · 257 unmodified lines
258 }258 }
259}259}
260 260
261// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of
262// invokeAnimationCallback requires that the type be registered.
263static QScriptValue animVarMapToScriptValue(QScriptEngine* engine, const AnimVariantMap& parameters) {
264 return parameters.animVariantMapToScriptValue(engine);
265}
266static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap& parameters) {
267 parameters.animVariantMapFromScriptValue(value);
268}
269
261void ScriptEngine::init() {270void ScriptEngine::init() {
262 if (_isInitialized) {271 if (_isInitialized) {
263 return; // only initialize once272 return; // only initialize once
@@ -316,6 +325,7 @@ void ScriptEngine::init() { · 52 unmodified lines
316 registerGlobalObject("Vec3", &_vec3Library);325 registerGlobalObject("Vec3", &_vec3Library);
317 registerGlobalObject("Uuid", &_uuidLibrary);326 registerGlobalObject("Uuid", &_uuidLibrary);
318 registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());327 registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
328 qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue);
319 329
320 // constants330 // constants
321 globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));331 globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
@@ -718,6 +728,21 @@ void ScriptEngine::stop() { · 396 unmodified lines
718 }728 }
719}729}
720 730
731// Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread.
732void ScriptEngine::invokeAnimationCallback(QScriptValue callback, AnimVariantMap parameters) {
733 checkThread();
734 QScriptValue javascriptParametgers = parameters.animVariantMapToScriptValue(this);
735 QScriptValueList callingArguments;
736 callingArguments << javascriptParametgers;
737 QScriptValue result = callback.call(QScriptValue(), callingArguments);
738 // We want to give the result back to the rig, but we don't have the rig or the avatar. But the global does.
739 // This is sort of like going through DependencyManager.get.
740 QScriptValue resultHandler = globalObject().property("MyAvatar").property("animationStateHandlerResult");
741 QScriptValueList resultArguments;
742 resultArguments << callback << result;
743 resultHandler.call(QScriptValue(), resultArguments); // Call it synchronously, on our own time and thread.
744}
745
721void ScriptEngine::timerFired() {746void ScriptEngine::timerFired() {
722 QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());747 QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
723 QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);748 QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
@@ -898,14 +923,20 @@ void ScriptEngine::load(const QString& loadFile) { · 174 unmodified lines
898 }923 }
899}924}
900 925
901// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args926bool ScriptEngine::checkThread() const {
902void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
903 if (QThread::currentThread() != thread()) {927 if (QThread::currentThread() != thread()) {
904 qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";928 qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
905 assert(false);929 assert(false);
906 return;930 return true;
907 }931 }
932 return false;
933}
908 934
935// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
936void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
937 if (checkThread()) {
938 return;
939 }
909 if (!_registeredHandlers.contains(entityID)) {940 if (!_registeredHandlers.contains(entityID)) {
910 return;941 return;
911 }942 }