History

resolve conflicts on merge with upstream/master

Stephen Birarda committed 11 years ago

Commit cee029f2 parents 7986b61 170725457 files · +855 −682Browse files

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

Unified · Split

libraries/script-engine/src/ScriptEngine.cpp+295−295
@@ -58,13 +58,13 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ · 57 unmodified lines
58 message += context->argument(i).toString();58 message += context->argument(i).toString();
59 }59 }
60 qCDebug(scriptengine) << "script:print()<<" << message;60 qCDebug(scriptengine) << "script:print()<<" << message;
61 61
62 message = message.replace("\\", "\\\\")62 message = message.replace("\\", "\\\\")
63 .replace("\n", "\\n")63 .replace("\n", "\\n")
64 .replace("\r", "\\r")64 .replace("\r", "\\r")
65 .replace("'", "\\'");65 .replace("'", "\\'");
66 engine->evaluate("Script.print('" + message + "')");66 engine->evaluate("Script.print('" + message + "')");
67 67
68 return QScriptValue();68 return QScriptValue();
69}69}
70 70
@@ -83,20 +83,51 @@ void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputCon · 12 unmodified lines
83 out = qobject_cast<AbstractInputController*>(object.toQObject());83 out = qobject_cast<AbstractInputController*>(object.toQObject());
84}84}
85 85
86ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,86static bool hasCorrectSyntax(const QScriptProgram& program) {
87 AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) :87 const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode());
88 if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
89 const auto error = syntaxCheck.errorMessage();
90 const auto line = QString::number(syntaxCheck.errorLineNumber());
91 const auto column = QString::number(syntaxCheck.errorColumnNumber());
92 const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column);
93 qCWarning(scriptengine) << qPrintable(message);
94 return false;
95 }
96 return true;
97}
88 98
89 _scriptContents(scriptContents),99static bool hadUncauchtExceptions(QScriptEngine& engine, const QString& fileName) {
90 _isFinished(false),100 if (engine.hasUncaughtException()) {
91 _isRunning(false),101 const auto backtrace = engine.uncaughtExceptionBacktrace();
92 _isInitialized(false),102 const auto exception = engine.uncaughtException().toString();
93 _timerFunctionMap(),103 const auto line = QString::number(engine.uncaughtExceptionLineNumber());
94 _wantSignals(wantSignals),104 engine.clearExceptions();
95 _controllerScriptingInterface(controllerScriptingInterface),105
96 _fileNameString(fileNameString),106 auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
97 _isUserLoaded(false),107 if (!backtrace.empty()) {
98 _isReloading(false),108 static const auto lineSeparator = "\n ";
99 _arrayBufferClass(new ArrayBufferClass(this))109 message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
110 }
111 qCWarning(scriptengine) << qPrintable(message);
112 return true;
113 }
114 return false;
115}
116
117ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
118 AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) :
119
120_scriptContents(scriptContents),
121_isFinished(false),
122_isRunning(false),
123_isInitialized(false),
124_timerFunctionMap(),
125_wantSignals(wantSignals),
126_controllerScriptingInterface(controllerScriptingInterface),
127_fileNameString(fileNameString),
128_isUserLoaded(false),
129_isReloading(false),
130_arrayBufferClass(new ArrayBufferClass(this))
100{131{
101 _allScriptsMutex.lock();132 _allScriptsMutex.lock();
102 _allKnownScriptEngines.insert(this);133 _allKnownScriptEngines.insert(this);
@@ -118,21 +149,21 @@ void ScriptEngine::runInThread() { · 15 unmodified lines
118 QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete149 QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete
119 QString scriptEngineName = QString("Script Thread:") + getFilename();150 QString scriptEngineName = QString("Script Thread:") + getFilename();
120 workerThread->setObjectName(scriptEngineName);151 workerThread->setObjectName(scriptEngineName);
121 152
122 // when the worker thread is started, call our engine's run..153 // when the worker thread is started, call our engine's run..
123 connect(workerThread, &QThread::started, this, &ScriptEngine::run);154 connect(workerThread, &QThread::started, this, &ScriptEngine::run);
124 155
125 // tell the thread to stop when the script engine is done156 // tell the thread to stop when the script engine is done
126 connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);157 connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
127 158
128 // when the thread is finished, add thread to the deleteLater queue159 // when the thread is finished, add thread to the deleteLater queue
129 connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);160 connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
130 161
131 // when the thread is finished, add scriptEngine to the deleteLater queue162 // when the thread is finished, add scriptEngine to the deleteLater queue
132 connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater);163 connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater);
133 164
134 moveToThread(workerThread);165 moveToThread(workerThread);
135 166
136 // Starts an event loop, and emits workerThread->started()167 // Starts an event loop, and emits workerThread->started()
137 workerThread->start();168 workerThread->start();
138}169}
@@ -145,23 +176,23 @@ bool ScriptEngine::_doneRunningThisScript = false; · 6 unmodified lines
145void ScriptEngine::stopAllScripts(QObject* application) {176void ScriptEngine::stopAllScripts(QObject* application) {
146 _allScriptsMutex.lock();177 _allScriptsMutex.lock();
147 _stoppingAllScripts = true;178 _stoppingAllScripts = true;
148 179
149 QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);180 QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
150 while (i.hasNext()) {181 while (i.hasNext()) {
151 ScriptEngine* scriptEngine = i.next();182 ScriptEngine* scriptEngine = i.next();
152 183
153 QString scriptName = scriptEngine->getFilename();184 QString scriptName = scriptEngine->getFilename();
154 185
155 // NOTE: typically all script engines are running. But there's at least one known exception to this, the186 // NOTE: typically all script engines are running. But there's at least one known exception to this, the
156 // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using187 // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using
157 // them. We don't need to stop scripts that aren't running.188 // them. We don't need to stop scripts that aren't running.
158 if (scriptEngine->isRunning()) {189 if (scriptEngine->isRunning()) {
159 190
160 // If the script is running, but still evaluating then we need to wait for its evaluation step to191 // If the script is running, but still evaluating then we need to wait for its evaluation step to
161 // complete. After that we can handle the stop process appropriately192 // complete. After that we can handle the stop process appropriately
162 if (scriptEngine->evaluatePending()) {193 if (scriptEngine->evaluatePending()) {
163 while (scriptEngine->evaluatePending()) {194 while (scriptEngine->evaluatePending()) {
164 195
165 // This event loop allows any started, but not yet finished evaluate() calls to complete196 // This event loop allows any started, but not yet finished evaluate() calls to complete
166 // we need to let these complete so that we can be guaranteed that the script engine isn't197 // we need to let these complete so that we can be guaranteed that the script engine isn't
167 // in a partially setup state, which can confuse our shutdown unwinding.198 // in a partially setup state, which can confuse our shutdown unwinding.
@@ -170,21 +201,21 @@ void ScriptEngine::stopAllScripts(QObject* application) { · 2 unmodified lines
170 loop.exec();201 loop.exec();
171 }202 }
172 }203 }
173 204
174 // We disconnect any script engine signals from the application because we don't want to do any205 // We disconnect any script engine signals from the application because we don't want to do any
175 // extra stopScript/loadScript processing that the Application normally does when scripts start206 // extra stopScript/loadScript processing that the Application normally does when scripts start
176 // and stop. We can safely short circuit this because we know we're in the "quitting" process207 // and stop. We can safely short circuit this because we know we're in the "quitting" process
177 scriptEngine->disconnect(application);208 scriptEngine->disconnect(application);
178 209
179 // Calling stop on the script engine will set it's internal _isFinished state to true, and result210 // Calling stop on the script engine will set it's internal _isFinished state to true, and result
180 // in the ScriptEngine gracefully ending it's run() method.211 // in the ScriptEngine gracefully ending it's run() method.
181 scriptEngine->stop();212 scriptEngine->stop();
182 213
183 // We need to wait for the engine to be done running before we proceed, because we don't214 // We need to wait for the engine to be done running before we proceed, because we don't
184 // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing215 // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing
185 // any application state after we leave this stopAllScripts() method216 // any application state after we leave this stopAllScripts() method
186 scriptEngine->waitTillDoneRunning();217 scriptEngine->waitTillDoneRunning();
187 218
188 // If the script is stopped, we can remove it from our set219 // If the script is stopped, we can remove it from our set
189 i.remove();220 i.remove();
190 }221 }
@@ -197,15 +228,15 @@ void ScriptEngine::stopAllScripts(QObject* application) { · 6 unmodified lines
197void ScriptEngine::waitTillDoneRunning() {228void ScriptEngine::waitTillDoneRunning() {
198 // If the script never started running or finished running before we got here, we don't need to wait for it229 // If the script never started running or finished running before we got here, we don't need to wait for it
199 if (_isRunning) {230 if (_isRunning) {
200 231
201 _doneRunningThisScript = false; // NOTE: this is static, we serialize our waiting for scripts to finish232 _doneRunningThisScript = false; // NOTE: this is static, we serialize our waiting for scripts to finish
202 233
203 // NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts()234 // NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts()
204 // we want the application thread to continue to process events, because the scripts will likely need to235 // we want the application thread to continue to process events, because the scripts will likely need to
205 // marshall messages across to the main thread. For example if they access Settings or Meny in any of their236 // marshall messages across to the main thread. For example if they access Settings or Meny in any of their
206 // shutdown code.237 // shutdown code.
207 while (!_doneRunningThisScript) {238 while (!_doneRunningThisScript) {
208 239
209 // process events for the main application thread, allowing invokeMethod calls to pass between threads240 // process events for the main application thread, allowing invokeMethod calls to pass between threads
210 QCoreApplication::processEvents();241 QCoreApplication::processEvents();
211 }242 }
@@ -227,12 +258,12 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { · 15 unmodified lines
227 if (_isRunning) {258 if (_isRunning) {
228 return;259 return;
229 }260 }
230 261
231 _fileNameString = scriptURL.toString();262 _fileNameString = scriptURL.toString();
232 _isReloading = reload;263 _isReloading = reload;
233 264
234 QUrl url(scriptURL);265 QUrl url(scriptURL);
235 266
236 bool isPending;267 bool isPending;
237 auto scriptCache = DependencyManager::get<ScriptCache>();268 auto scriptCache = DependencyManager::get<ScriptCache>();
238 scriptCache->getScript(url, this, isPending, reload);269 scriptCache->getScript(url, this, isPending, reload);
@@ -258,12 +289,12 @@ void ScriptEngine::init() { · 19 unmodified lines
258 if (_isInitialized) {289 if (_isInitialized) {
259 return; // only initialize once290 return; // only initialize once
260 }291 }
261 292
262 _isInitialized = true;293 _isInitialized = true;
263 294
264 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();295 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
265 entityScriptingInterface->init();296 entityScriptingInterface->init();
266 297
267 // register various meta-types298 // register various meta-types
268 registerMetaTypes(this);299 registerMetaTypes(this);
269 registerMIDIMetaTypes(this);300 registerMIDIMetaTypes(this);
@@ -272,30 +303,30 @@ void ScriptEngine::init() { · 2 unmodified lines
272 registerAnimationTypes(this);303 registerAnimationTypes(this);
273 registerAvatarTypes(this);304 registerAvatarTypes(this);
274 registerAudioMetaTypes(this);305 registerAudioMetaTypes(this);
275 306
276 qScriptRegisterMetaType(this, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue);307 qScriptRegisterMetaType(this, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue);
277 qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);308 qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
278 qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);309 qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
279 qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);310 qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
280 qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);311 qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
281 qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this);312 qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this);
282 313
283 qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this);314 qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this);
284 qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this);315 qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this);
285 qScriptRegisterSequenceMetaType<QVector<QString> >(this);316 qScriptRegisterSequenceMetaType<QVector<QString> >(this);
286 317
287 QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor);318 QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor);
288 globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue);319 globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue);
289 320
290 QScriptValue webSocketConstructorValue = newFunction(WebSocketClass::constructor);321 QScriptValue webSocketConstructorValue = newFunction(WebSocketClass::constructor);
291 globalObject().setProperty("WebSocket", webSocketConstructorValue);322 globalObject().setProperty("WebSocket", webSocketConstructorValue);
292 323
293 QScriptValue printConstructorValue = newFunction(debugPrint);324 QScriptValue printConstructorValue = newFunction(debugPrint);
294 globalObject().setProperty("print", printConstructorValue);325 globalObject().setProperty("print", printConstructorValue);
295 326
296 QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor);327 QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor);
297 globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue);328 globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue);
298 329
299 qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue);330 qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue);
300 qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);331 qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);
301 qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue);332 qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue);
@@ -303,7 +334,7 @@ void ScriptEngine::init() { · 1 unmodified line
303 qScriptRegisterMetaType(this, webSocketToScriptValue, webSocketFromScriptValue);334 qScriptRegisterMetaType(this, webSocketToScriptValue, webSocketFromScriptValue);
304 qScriptRegisterMetaType(this, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue);335 qScriptRegisterMetaType(this, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue);
305 qScriptRegisterMetaType(this, wscReadyStateToScriptValue, wscReadyStateFromScriptValue);336 qScriptRegisterMetaType(this, wscReadyStateToScriptValue, wscReadyStateFromScriptValue);
306 337
307 registerGlobalObject("Script", this);338 registerGlobalObject("Script", this);
308 registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());339 registerGlobalObject("Audio", &AudioScriptingInterface::getInstance());
309 registerGlobalObject("Controller", _controllerScriptingInterface);340 registerGlobalObject("Controller", _controllerScriptingInterface);
@@ -312,15 +343,15 @@ void ScriptEngine::init() { · 2 unmodified lines
312 registerGlobalObject("Vec3", &_vec3Library);343 registerGlobalObject("Vec3", &_vec3Library);
313 registerGlobalObject("Uuid", &_uuidLibrary);344 registerGlobalObject("Uuid", &_uuidLibrary);
314 registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());345 registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
315 346
316 // constants347 // constants
317 globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));348 globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
318 349
319 if (_controllerScriptingInterface) {350 if (_controllerScriptingInterface) {
320 _controllerScriptingInterface->registerControllerTypes(this);351 _controllerScriptingInterface->registerControllerTypes(this);
321 }352 }
322 353
323 354
324}355}
325 356
326void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {357void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) {
@@ -329,15 +360,15 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { · 2 unmodified lines
329 qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;360 qDebug() << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
330#endif361#endif
331 QMetaObject::invokeMethod(this, "registerValue",362 QMetaObject::invokeMethod(this, "registerValue",
332 Q_ARG(const QString&, valueName),363 Q_ARG(const QString&, valueName),
333 Q_ARG(QScriptValue, value));364 Q_ARG(QScriptValue, value));
334 return;365 return;
335 }366 }
336 367
337 QStringList pathToValue = valueName.split(".");368 QStringList pathToValue = valueName.split(".");
338 int partsToGo = pathToValue.length();369 int partsToGo = pathToValue.length();
339 QScriptValue partObject = globalObject();370 QScriptValue partObject = globalObject();
340 371
341 for (const auto& pathPart : pathToValue) {372 for (const auto& pathPart : pathToValue) {
342 partsToGo--;373 partsToGo--;
343 if (!partObject.property(pathPart).isValid()) {374 if (!partObject.property(pathPart).isValid()) {
@@ -356,18 +387,18 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { · 12 unmodified lines
356 387
357void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {388void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
358 if (QThread::currentThread() != thread()) {389 if (QThread::currentThread() != thread()) {
359 #ifdef THREAD_DEBUGGING390#ifdef THREAD_DEBUGGING
360 qDebug() << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;391 qDebug() << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
361 #endif392#endif
362 QMetaObject::invokeMethod(this, "registerGlobalObject",393 QMetaObject::invokeMethod(this, "registerGlobalObject",
363 Q_ARG(const QString&, name),394 Q_ARG(const QString&, name),
364 Q_ARG(QObject*, object));395 Q_ARG(QObject*, object));
365 return;396 return;
366 }397 }
367 #ifdef THREAD_DEBUGGING398#ifdef THREAD_DEBUGGING
368 qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;399 qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
369 #endif400#endif
370 401
371 if (!globalObject().property(name).isValid()) {402 if (!globalObject().property(name).isValid()) {
372 if (object) {403 if (object) {
373 QScriptValue value = newQObject(object);404 QScriptValue value = newQObject(object);
@@ -380,38 +411,38 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { · 6 unmodified lines
380 411
381void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {412void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
382 if (QThread::currentThread() != thread()) {413 if (QThread::currentThread() != thread()) {
383 #ifdef THREAD_DEBUGGING414#ifdef THREAD_DEBUGGING
384 qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;415 qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name;
385 #endif416#endif
386 QMetaObject::invokeMethod(this, "registerFunction",417 QMetaObject::invokeMethod(this, "registerFunction",
387 Q_ARG(const QString&, name),418 Q_ARG(const QString&, name),
388 Q_ARG(QScriptEngine::FunctionSignature, functionSignature),419 Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
389 Q_ARG(int, numArguments));420 Q_ARG(int, numArguments));
390 return;421 return;
391 }422 }
392 #ifdef THREAD_DEBUGGING423#ifdef THREAD_DEBUGGING
393 qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;424 qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;
394 #endif425#endif
395 426
396 QScriptValue scriptFun = newFunction(functionSignature, numArguments);427 QScriptValue scriptFun = newFunction(functionSignature, numArguments);
397 globalObject().setProperty(name, scriptFun);428 globalObject().setProperty(name, scriptFun);
398}429}
399 430
400void ScriptEngine::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {431void ScriptEngine::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
401 if (QThread::currentThread() != thread()) {432 if (QThread::currentThread() != thread()) {
402 #ifdef THREAD_DEBUGGING433#ifdef THREAD_DEBUGGING
403 qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name;434 qDebug() << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name;
404 #endif435#endif
405 QMetaObject::invokeMethod(this, "registerFunction",436 QMetaObject::invokeMethod(this, "registerFunction",
406 Q_ARG(const QString&, name),437 Q_ARG(const QString&, name),
407 Q_ARG(QScriptEngine::FunctionSignature, functionSignature),438 Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
408 Q_ARG(int, numArguments));439 Q_ARG(int, numArguments));
409 return;440 return;
410 }441 }
411 #ifdef THREAD_DEBUGGING442#ifdef THREAD_DEBUGGING
412 qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;443 qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;
413 #endif444#endif
414 445
415 QScriptValue object = globalObject().property(parent);446 QScriptValue object = globalObject().property(parent);
416 if (object.isValid()) {447 if (object.isValid()) {
417 QScriptValue scriptFun = newFunction(functionSignature, numArguments);448 QScriptValue scriptFun = newFunction(functionSignature, numArguments);
@@ -420,26 +451,26 @@ void ScriptEngine::registerFunction(const QString& parent, const QString& name, · 2 unmodified lines
420}451}
421 452
422void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter,453void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter,
423 QScriptEngine::FunctionSignature setter, const QString& parent) {454 QScriptEngine::FunctionSignature setter, const QString& parent) {
424 if (QThread::currentThread() != thread()) {455 if (QThread::currentThread() != thread()) {
425 #ifdef THREAD_DEBUGGING456#ifdef THREAD_DEBUGGING
426 qDebug() << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "457 qDebug() << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
427 " name:" << name << "parent:" << parent;458 " name:" << name << "parent:" << parent;
428 #endif459#endif
429 QMetaObject::invokeMethod(this, "registerGetterSetter",460 QMetaObject::invokeMethod(this, "registerGetterSetter",
430 Q_ARG(const QString&, name),461 Q_ARG(const QString&, name),
431 Q_ARG(QScriptEngine::FunctionSignature, getter),462 Q_ARG(QScriptEngine::FunctionSignature, getter),
432 Q_ARG(QScriptEngine::FunctionSignature, setter),463 Q_ARG(QScriptEngine::FunctionSignature, setter),
433 Q_ARG(const QString&, parent));464 Q_ARG(const QString&, parent));
434 return;465 return;
435 }466 }
436 #ifdef THREAD_DEBUGGING467#ifdef THREAD_DEBUGGING
437 qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;468 qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;
438 #endif469#endif
439 470
440 QScriptValue setterFunction = newFunction(setter, 1);471 QScriptValue setterFunction = newFunction(setter, 1);
441 QScriptValue getterFunction = newFunction(getter);472 QScriptValue getterFunction = newFunction(getter);
442 473
443 if (!parent.isNull() && !parent.isEmpty()) {474 if (!parent.isNull() && !parent.isEmpty()) {
444 QScriptValue object = globalObject().property(parent);475 QScriptValue object = globalObject().property(parent);
445 if (object.isValid()) {476 if (object.isValid()) {
@@ -455,20 +486,20 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 9 unmodified lines
455// Unregister the handlers for this eventName and entityID.486// Unregister the handlers for this eventName and entityID.
456void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {487void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
457 if (QThread::currentThread() != thread()) {488 if (QThread::currentThread() != thread()) {
458 #ifdef THREAD_DEBUGGING489#ifdef THREAD_DEBUGGING
459 qDebug() << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "490 qDebug() << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
460 "entityID:" << entityID << " eventName:" << eventName;491 "entityID:" << entityID << " eventName:" << eventName;
461 #endif492#endif
462 QMetaObject::invokeMethod(this, "removeEventHandler",493 QMetaObject::invokeMethod(this, "removeEventHandler",
463 Q_ARG(const EntityItemID&, entityID),494 Q_ARG(const EntityItemID&, entityID),
464 Q_ARG(const QString&, eventName),495 Q_ARG(const QString&, eventName),
465 Q_ARG(QScriptValue, handler));496 Q_ARG(QScriptValue, handler));
466 return;497 return;
467 }498 }
468 #ifdef THREAD_DEBUGGING499#ifdef THREAD_DEBUGGING
469 qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;500 qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
470 #endif501#endif
471 502
472 if (!_registeredHandlers.contains(entityID)) {503 if (!_registeredHandlers.contains(entityID)) {
473 return;504 return;
474 }505 }
@@ -485,21 +516,21 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin · 10 unmodified lines
485// Register the handler.516// Register the handler.
486void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {517void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
487 if (QThread::currentThread() != thread()) {518 if (QThread::currentThread() != thread()) {
488 #ifdef THREAD_DEBUGGING519#ifdef THREAD_DEBUGGING
489 qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "520 qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
490 "entityID:" << entityID << " eventName:" << eventName;521 "entityID:" << entityID << " eventName:" << eventName;
491 #endif522#endif
492 523
493 QMetaObject::invokeMethod(this, "addEventHandler",524 QMetaObject::invokeMethod(this, "addEventHandler",
494 Q_ARG(const EntityItemID&, entityID),525 Q_ARG(const EntityItemID&, entityID),
495 Q_ARG(const QString&, eventName),526 Q_ARG(const QString&, eventName),
496 Q_ARG(QScriptValue, handler));527 Q_ARG(QScriptValue, handler));
497 return;528 return;
498 }529 }
499 #ifdef THREAD_DEBUGGING530#ifdef THREAD_DEBUGGING
500 qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;531 qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName;
501 #endif532#endif
502 533
503 if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script...534 if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script...
504 // Connect up ALL the handlers to the global entities object's signals.535 // Connect up ALL the handlers to the global entities object's signals.
505 // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.)536 // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.)
@@ -527,25 +558,25 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 21 unmodified lines
527 auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler {558 auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler {
528 return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) {559 return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) {
529 forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this),560 forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this),
530 collisionToScriptValue(this, collision) });561 collisionToScriptValue(this, collision) });
531 };562 };
532 };563 };
533 564
534 connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity"));565 connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity"));
535 connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity"));566 connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity"));
536 567
537 connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity"));568 connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity"));
538 connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity"));569 connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity"));
539 connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity"));570 connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity"));
540 571
541 connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity"));572 connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity"));
542 connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity"));573 connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity"));
543 connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity"));574 connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity"));
544 575
545 connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity"));576 connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity"));
546 connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity"));577 connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity"));
547 connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity"));578 connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity"));
548 579
549 connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity"));580 connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity"));
550 }581 }
551 if (!_registeredHandlers.contains(entityID)) {582 if (!_registeredHandlers.contains(entityID)) {
@@ -560,32 +591,32 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 8 unmodified lines
560 if (_stoppingAllScripts) {591 if (_stoppingAllScripts) {
561 return QScriptValue(); // bail early592 return QScriptValue(); // bail early
562 }593 }
563 594
564 if (QThread::currentThread() != thread()) {595 if (QThread::currentThread() != thread()) {
565 QScriptValue result;596 QScriptValue result;
566 #ifdef THREAD_DEBUGGING597#ifdef THREAD_DEBUGGING
567 qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "598 qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
568 "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber;599 "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber;
569 #endif600#endif
570 QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection,601 QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection,
571 Q_RETURN_ARG(QScriptValue, result),602 Q_RETURN_ARG(QScriptValue, result),
572 Q_ARG(const QString&, sourceCode),603 Q_ARG(const QString&, sourceCode),
573 Q_ARG(const QString&, fileName),604 Q_ARG(const QString&, fileName),
574 Q_ARG(int, lineNumber));605 Q_ARG(int, lineNumber));
575 return result;606 return result;
576 }607 }
577 608
578 // Check syntax609 // Check syntax
579 const QScriptProgram program(sourceCode, fileName, lineNumber);610 const QScriptProgram program(sourceCode, fileName, lineNumber);
580 if (!checkSyntax(program)) {611 if (!hasCorrectSyntax(program)) {
581 return QScriptValue();612 return QScriptValue();
582 }613 }
583 614
584 ++_evaluatesPending;615 ++_evaluatesPending;
585 const auto result = QScriptEngine::evaluate(program);616 const auto result = QScriptEngine::evaluate(program);
586 --_evaluatesPending;617 --_evaluatesPending;
587 618
588 const auto hadUncaughtException = checkExceptions(*this, program.fileName());619 const auto hadUncaughtException = hadUncauchtExceptions(*this, program.fileName());
589 if (_wantSignals) {620 if (_wantSignals) {
590 emit evaluationFinished(result, hadUncaughtException);621 emit evaluationFinished(result, hadUncaughtException);
591 }622 }
@@ -595,7 +626,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 3 unmodified lines
595void ScriptEngine::run() {626void ScriptEngine::run() {
596 // TODO: can we add a short circuit for _stoppingAllScripts here? What does it mean to not start running if627 // TODO: can we add a short circuit for _stoppingAllScripts here? What does it mean to not start running if
597 // we're in the process of stopping?628 // we're in the process of stopping?
598 629
599 if (!_isInitialized) {630 if (!_isInitialized) {
600 init();631 init();
601 }632 }
@@ -605,69 +636,69 @@ void ScriptEngine::run() { · 3 unmodified lines
605 if (_wantSignals) {636 if (_wantSignals) {
606 emit runningStateChanged();637 emit runningStateChanged();
607 }638 }
608 639
609 QScriptValue result = evaluate(_scriptContents, _fileNameString);640 QScriptValue result = evaluate(_scriptContents, _fileNameString);
610 641
611 QElapsedTimer startTime;642 QElapsedTimer startTime;
612 startTime.start();643 startTime.start();
613 644
614 int thisFrame = 0;645 int thisFrame = 0;
615 646
616 auto nodeList = DependencyManager::get<NodeList>();647 auto nodeList = DependencyManager::get<NodeList>();
617 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();648 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
618 649
619 qint64 lastUpdate = usecTimestampNow();650 qint64 lastUpdate = usecTimestampNow();
620 651
621 while (!_isFinished) {652 while (!_isFinished) {
622 int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec653 int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
623 if (usecToSleep > 0) {654 if (usecToSleep > 0) {
624 usleep(usecToSleep);655 usleep(usecToSleep);
625 }656 }
626 657
627 if (_isFinished) {658 if (_isFinished) {
628 break;659 break;
629 }660 }
630 661
631 QCoreApplication::processEvents();662 QCoreApplication::processEvents();
632 663
633 if (_isFinished) {664 if (_isFinished) {
634 break;665 break;
635 }666 }
636 667
637 if (!_isFinished && entityScriptingInterface->getEntityPacketSender()->serversExist()) {668 if (!_isFinished && entityScriptingInterface->getEntityPacketSender()->serversExist()) {
638 // release the queue of edit entity messages.669 // release the queue of edit entity messages.
639 entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages();670 entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages();
640 671
641 // since we're in non-threaded mode, call process so that the packets are sent672 // since we're in non-threaded mode, call process so that the packets are sent
642 if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) {673 if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) {
643 entityScriptingInterface->getEntityPacketSender()->process();674 entityScriptingInterface->getEntityPacketSender()->process();
644 }675 }
645 }676 }
646 677
647 qint64 now = usecTimestampNow();678 qint64 now = usecTimestampNow();
648 float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND;679 float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND;
649 680
650 if (!_isFinished) {681 if (!_isFinished) {
651 if (_wantSignals) {682 if (_wantSignals) {
652 emit update(deltaTime);683 emit update(deltaTime);
653 }684 }
654 }685 }
655 lastUpdate = now;686 lastUpdate = now;
656 687
657 if (!checkExceptions(*this, _fileNameString)) {688 if (hadUncauchtExceptions(*this, _fileNameString)) {
658 stop();689 stop();
659 }690 }
660 }691 }
661 692
662 stopAllTimers(); // make sure all our timers are stopped if the script is ending693 stopAllTimers(); // make sure all our timers are stopped if the script is ending
663 if (_wantSignals) {694 if (_wantSignals) {
664 emit scriptEnding();695 emit scriptEnding();
665 }696 }
666 697
667 if (entityScriptingInterface->getEntityPacketSender()->serversExist()) {698 if (entityScriptingInterface->getEntityPacketSender()->serversExist()) {
668 // release the queue of edit entity messages.699 // release the queue of edit entity messages.
669 entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages();700 entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages();
670 701
671 // since we're in non-threaded mode, call process so that the packets are sent702 // since we're in non-threaded mode, call process so that the packets are sent
672 if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) {703 if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) {
673 // wait here till the edit packet sender is completely done sending704 // wait here till the edit packet sender is completely done sending
@@ -679,17 +710,17 @@ void ScriptEngine::run() { · 5 unmodified lines
679 // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders?710 // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders?
680 }711 }
681 }712 }
682 713
683 if (_wantSignals) {714 if (_wantSignals) {
684 emit finished(_fileNameString);715 emit finished(_fileNameString);
685 }716 }
686 717
687 _isRunning = false;718 _isRunning = false;
688 if (_wantSignals) {719 if (_wantSignals) {
689 emit runningStateChanged();720 emit runningStateChanged();
690 emit doneRunning();721 emit doneRunning();
691 }722 }
692 723
693 _doneRunningThisScript = true;724 _doneRunningThisScript = true;
694}725}
695 726
@@ -716,13 +747,13 @@ void ScriptEngine::stop() { · 20 unmodified lines
716void ScriptEngine::timerFired() {747void ScriptEngine::timerFired() {
717 QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());748 QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
718 QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);749 QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
719 750
720 if (!callingTimer->isActive()) {751 if (!callingTimer->isActive()) {
721 // this timer is done, we can kill it752 // this timer is done, we can kill it
722 _timerFunctionMap.remove(callingTimer);753 _timerFunctionMap.remove(callingTimer);
723 delete callingTimer;754 delete callingTimer;
724 }755 }
725 756
726 // call the associated JS function, if it exists757 // call the associated JS function, if it exists
727 if (timerFunction.isValid()) {758 if (timerFunction.isValid()) {
728 timerFunction.call();759 timerFunction.call();
@@ -733,14 +764,14 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 4 unmodified lines
733 // create the timer, add it to the map, and start it764 // create the timer, add it to the map, and start it
734 QTimer* newTimer = new QTimer(this);765 QTimer* newTimer = new QTimer(this);
735 newTimer->setSingleShot(isSingleShot);766 newTimer->setSingleShot(isSingleShot);
736 767
737 connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);768 connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
738 769
739 // make sure the timer stops when the script does770 // make sure the timer stops when the script does
740 connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);771 connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
741 772
742 _timerFunctionMap.insert(newTimer, function);773 _timerFunctionMap.insert(newTimer, function);
743 774
744 newTimer->start(intervalMS);775 newTimer->start(intervalMS);
745 return newTimer;776 return newTimer;
746}777}
@@ -750,7 +781,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) · 3 unmodified lines
750 qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename();781 qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename();
751 return NULL; // bail early782 return NULL; // bail early
752 }783 }
753 784
754 return setupTimerWithInterval(function, intervalMS, false);785 return setupTimerWithInterval(function, intervalMS, false);
755}786}
756 787
@@ -759,7 +790,7 @@ QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { · 2 unmodified lines
759 qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename();790 qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename();
760 return NULL; // bail early791 return NULL; // bail early
761 }792 }
762 793
763 return setupTimerWithInterval(function, timeoutMS, true);794 return setupTimerWithInterval(function, timeoutMS, true);
764}795}
765 796
@@ -777,7 +808,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { · 11 unmodified lines
777 if (!url.scheme().isEmpty()) {808 if (!url.scheme().isEmpty()) {
778 return url;809 return url;
779 }810 }
780 811
781 // we apparently weren't a fully qualified url, so, let's assume we're relative812 // we apparently weren't a fully qualified url, so, let's assume we're relative
782 // to the original URL of our script813 // to the original URL of our script
783 QUrl parentURL;814 QUrl parentURL;
@@ -790,7 +821,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { · 6 unmodified lines
790 if (parentURL.scheme().isEmpty()) {821 if (parentURL.scheme().isEmpty()) {
791 parentURL = QUrl::fromLocalFile(_fileNameString);822 parentURL = QUrl::fromLocalFile(_fileNameString);
792 }823 }
793 824
794 // at this point we should have a legitimate fully qualified URL for our parent825 // at this point we should have a legitimate fully qualified URL for our parent
795 url = parentURL.resolved(url);826 url = parentURL.resolved(url);
796 return url;827 return url;
@@ -809,7 +840,7 @@ void ScriptEngine::print(const QString& message) { · 12 unmodified lines
809void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {840void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {
810 if (_stoppingAllScripts) {841 if (_stoppingAllScripts) {
811 qCDebug(scriptengine) << "Script.include() while shutting down is ignored..."842 qCDebug(scriptengine) << "Script.include() while shutting down is ignored..."
812 << "includeFiles:" << includeFiles << "parent script:" << getFilename();843 << "includeFiles:" << includeFiles << "parent script:" << getFilename();
813 return; // bail early844 return; // bail early
814 }845 }
815 QList<QUrl> urls;846 QList<QUrl> urls;
@@ -823,9 +854,9 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 7 unmodified lines
823 qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL;854 qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL;
824 }855 }
825 }856 }
826 857
827 BatchLoader* loader = new BatchLoader(urls);858 BatchLoader* loader = new BatchLoader(urls);
828 859
829 auto evaluateScripts = [=](const QMap<QUrl, QString>& data) {860 auto evaluateScripts = [=](const QMap<QUrl, QString>& data) {
830 for (QUrl url : urls) {861 for (QUrl url : urls) {
831 QString contents = data[url];862 QString contents = data[url];
@@ -835,21 +866,21 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 3 unmodified lines
835 QScriptValue result = evaluate(contents, url.toString());866 QScriptValue result = evaluate(contents, url.toString());
836 }867 }
837 }868 }
838 869
839 if (callback.isFunction()) {870 if (callback.isFunction()) {
840 QScriptValue(callback).call();871 QScriptValue(callback).call();
841 }872 }
842 873
843 loader->deleteLater();874 loader->deleteLater();
844 };875 };
845 876
846 connect(loader, &BatchLoader::finished, this, evaluateScripts);877 connect(loader, &BatchLoader::finished, this, evaluateScripts);
847 878
848 // If we are destroyed before the loader completes, make sure to clean it up879 // If we are destroyed before the loader completes, make sure to clean it up
849 connect(this, &QObject::destroyed, loader, &QObject::deleteLater);880 connect(this, &QObject::destroyed, loader, &QObject::deleteLater);
850 881
851 loader->start();882 loader->start();
852 883
853 if (!callback.isFunction() && !loader->isFinished()) {884 if (!callback.isFunction() && !loader->isFinished()) {
854 QEventLoop loop;885 QEventLoop loop;
855 QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit);886 QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit);
@@ -860,10 +891,10 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 4 unmodified lines
860void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {891void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
861 if (_stoppingAllScripts) {892 if (_stoppingAllScripts) {
862 qCDebug(scriptengine) << "Script.include() while shutting down is ignored... "893 qCDebug(scriptengine) << "Script.include() while shutting down is ignored... "
863 << "includeFile:" << includeFile << "parent script:" << getFilename();894 << "includeFile:" << includeFile << "parent script:" << getFilename();
864 return; // bail early895 return; // bail early
865 }896 }
866 897
867 QStringList urls;898 QStringList urls;
868 urls.append(includeFile);899 urls.append(includeFile);
869 include(urls, callback);900 include(urls, callback);
@@ -875,10 +906,10 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { · 5 unmodified lines
875void ScriptEngine::load(const QString& loadFile) {906void ScriptEngine::load(const QString& loadFile) {
876 if (_stoppingAllScripts) {907 if (_stoppingAllScripts) {
877 qCDebug(scriptengine) << "Script.load() while shutting down is ignored... "908 qCDebug(scriptengine) << "Script.load() while shutting down is ignored... "
878 << "loadFile:" << loadFile << "parent script:" << getFilename();909 << "loadFile:" << loadFile << "parent script:" << getFilename();
879 return; // bail early910 return; // bail early
880 }911 }
881 912
882 QUrl url = resolvePath(loadFile);913 QUrl url = resolvePath(loadFile);
883 if (_isReloading) {914 if (_isReloading) {
884 auto scriptCache = DependencyManager::get<ScriptCache>();915 auto scriptCache = DependencyManager::get<ScriptCache>();
@@ -893,37 +924,6 @@ void ScriptEngine::load(const QString& loadFile) { · 8 unmodified lines
893 }924 }
894}925}
895 926
896bool ScriptEngine::checkSyntax(const QScriptProgram& program) {
897 const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode());
898 if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
899 const auto error = syntaxCheck.errorMessage();
900 const auto line = QString::number(syntaxCheck.errorLineNumber());
901 const auto column = QString::number(syntaxCheck.errorColumnNumber());
902 const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column);
903 qCWarning(scriptengine) << qPrintable(message);
904 return false;
905 }
906 return true;
907}
908
909bool ScriptEngine::checkExceptions(QScriptEngine& engine, const QString& fileName) {
910 if (engine.hasUncaughtException()) {
911 const auto backtrace = engine.uncaughtExceptionBacktrace();
912 const auto exception = engine.uncaughtException().toString();
913 const auto line = QString::number(engine.uncaughtExceptionLineNumber());
914 engine.clearExceptions();
915
916 auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
917 if (!backtrace.empty()) {
918 static const auto lineSeparator = "\n ";
919 message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
920 }
921 qCWarning(scriptengine) << qPrintable(message);
922 return false;
923 }
924 return true;
925}
926
927// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args927// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
928void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) {928void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) {
929 if (QThread::currentThread() != thread()) {929 if (QThread::currentThread() != thread()) {
@@ -931,7 +931,7 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin · 1 unmodified line
931 assert(false);931 assert(false);
932 return;932 return;
933 }933 }
934 934
935 if (!_registeredHandlers.contains(entityID)) {935 if (!_registeredHandlers.contains(entityID)) {
936 return;936 return;
937 }937 }
@@ -951,97 +951,97 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin · 13 unmodified lines
951// for the download951// for the download
952void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) {952void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) {
953 if (QThread::currentThread() != thread()) {953 if (QThread::currentThread() != thread()) {
954 #ifdef THREAD_DEBUGGING954#ifdef THREAD_DEBUGGING
955 qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "955 qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
956 "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload;956 "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload;
957 #endif957#endif
958 958
959 QMetaObject::invokeMethod(this, "loadEntityScript",959 QMetaObject::invokeMethod(this, "loadEntityScript",
960 Q_ARG(const EntityItemID&, entityID),960 Q_ARG(const EntityItemID&, entityID),
961 Q_ARG(const QString&, entityScript),961 Q_ARG(const QString&, entityScript),
962 Q_ARG(bool, forceRedownload));962 Q_ARG(bool, forceRedownload));
963 return;963 return;
964 }964 }
965 #ifdef THREAD_DEBUGGING965#ifdef THREAD_DEBUGGING
966 qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] "966 qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] "
967 "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload;967 "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload;
968 #endif968#endif
969 969
970 // If we've been called our known entityScripts should not know about us..970 // If we've been called our known entityScripts should not know about us..
971 assert(!_entityScripts.contains(entityID));971 assert(!_entityScripts.contains(entityID));
972 972
973 #ifdef THREAD_DEBUGGING973#ifdef THREAD_DEBUGGING
974 qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";974 qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
975 #endif975#endif
976 DependencyManager::get<ScriptCache>()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {976 DependencyManager::get<ScriptCache>()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {
977 #ifdef THREAD_DEBUGGING977#ifdef THREAD_DEBUGGING
978 qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";978 qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
979 #endif979#endif
980 980
981 this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);981 this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success);
982 }, forceRedownload);982 }, forceRedownload);
983}983}
984 984
985// since all of these operations can be asynch we will always do the actual work in the response handler985// since all of these operations can be asynch we will always do the actual work in the response handler
986// for the download986// for the download
987void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {987void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) {
988 if (QThread::currentThread() != thread()) {988 if (QThread::currentThread() != thread()) {
989 #ifdef THREAD_DEBUGGING989#ifdef THREAD_DEBUGGING
990 qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "990 qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
991 "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success;991 "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success;
992 #endif992#endif
993 993
994 QMetaObject::invokeMethod(this, "entityScriptContentAvailable",994 QMetaObject::invokeMethod(this, "entityScriptContentAvailable",
995 Q_ARG(const EntityItemID&, entityID),995 Q_ARG(const EntityItemID&, entityID),
996 Q_ARG(const QString&, scriptOrURL),996 Q_ARG(const QString&, scriptOrURL),
997 Q_ARG(const QString&, contents),997 Q_ARG(const QString&, contents),
998 Q_ARG(bool, isURL),998 Q_ARG(bool, isURL),
999 Q_ARG(bool, success));999 Q_ARG(bool, success));
1000 return;1000 return;
1001 }1001 }
1002 1002
1003 #ifdef THREAD_DEBUGGING1003#ifdef THREAD_DEBUGGING
1004 qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";1004 qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
1005 #endif1005#endif
1006 1006
1007 auto scriptCache = DependencyManager::get<ScriptCache>();1007 auto scriptCache = DependencyManager::get<ScriptCache>();
1008 bool isFileUrl = isURL && scriptOrURL.startsWith("file://");1008 bool isFileUrl = isURL && scriptOrURL.startsWith("file://");
1009 auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript");1009 auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript");
1010 1010
1011 QScriptProgram program(contents, fileName);1011 QScriptProgram program(contents, fileName);
1012 if (!checkSyntax(program)) {1012 if (!hasCorrectSyntax(program)) {
1013 if (!isFileUrl) {1013 if (!isFileUrl) {
1014 scriptCache->addScriptToBadScriptList(scriptOrURL);1014 scriptCache->addScriptToBadScriptList(scriptOrURL);
1015 }1015 }
1016 return; // done processing script1016 return; // done processing script
1017 }1017 }
1018 1018
1019 if (isURL) {1019 if (isURL) {
1020 setParentURL(scriptOrURL);1020 setParentURL(scriptOrURL);
1021 }1021 }
1022 1022
1023 QScriptEngine sandbox;1023 QScriptEngine sandbox;
1024 QScriptValue testConstructor = sandbox.evaluate(program);1024 QScriptValue testConstructor = sandbox.evaluate(program);
1025 if (!checkExceptions(sandbox, program.fileName())) {1025 if (hadUncauchtExceptions(sandbox, program.fileName())) {
1026 return;1026 return;
1027 }1027 }
1028 1028
1029 if (!testConstructor.isFunction()) {1029 if (!testConstructor.isFunction()) {
1030 qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n"1030 qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n"
1031 " NOT CONSTRUCTOR\n"1031 " NOT CONSTRUCTOR\n"
1032 " SCRIPT:" << scriptOrURL;1032 " SCRIPT:" << scriptOrURL;
1033 if (!isFileUrl) {1033 if (!isFileUrl) {
1034 scriptCache->addScriptToBadScriptList(scriptOrURL);1034 scriptCache->addScriptToBadScriptList(scriptOrURL);
1035 }1035 }
1036 return; // done processing script1036 return; // done processing script
1037 }1037 }
1038 1038
1039 int64_t lastModified = 0;1039 int64_t lastModified = 0;
1040 if (isFileUrl) {1040 if (isFileUrl) {
1041 QString file = QUrl(scriptOrURL).toLocalFile();1041 QString file = QUrl(scriptOrURL).toLocalFile();
1042 lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();1042 lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch();
1043 }1043 }
1044 1044
1045 QScriptValue entityScriptConstructor = evaluate(contents, fileName);1045 QScriptValue entityScriptConstructor = evaluate(contents, fileName);
1046 QScriptValue entityScriptObject = entityScriptConstructor.construct();1046 QScriptValue entityScriptObject = entityScriptConstructor.construct();
1047 EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified };1047 EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified };
@@ -1049,27 +1049,27 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 1 unmodified line
1049 if (isURL) {1049 if (isURL) {
1050 setParentURL("");1050 setParentURL("");
1051 }1051 }
1052 1052
1053 // if we got this far, then call the preload method1053 // if we got this far, then call the preload method
1054 callEntityScriptMethod(entityID, "preload");1054 callEntityScriptMethod(entityID, "preload");
1055}1055}
1056 1056
1057void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {1057void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
1058 if (QThread::currentThread() != thread()) {1058 if (QThread::currentThread() != thread()) {
1059 #ifdef THREAD_DEBUGGING1059#ifdef THREAD_DEBUGGING
1060 qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "1060 qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
1061 "entityID:" << entityID;1061 "entityID:" << entityID;
1062 #endif1062#endif
1063 1063
1064 QMetaObject::invokeMethod(this, "unloadEntityScript",1064 QMetaObject::invokeMethod(this, "unloadEntityScript",
1065 Q_ARG(const EntityItemID&, entityID));1065 Q_ARG(const EntityItemID&, entityID));
1066 return;1066 return;
1067 }1067 }
1068 #ifdef THREAD_DEBUGGING1068#ifdef THREAD_DEBUGGING
1069 qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] "1069 qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] "
1070 "entityID:" << entityID;1070 "entityID:" << entityID;
1071 #endif1071#endif
1072 1072
1073 if (_entityScripts.contains(entityID)) {1073 if (_entityScripts.contains(entityID)) {
1074 callEntityScriptMethod(entityID, "unload");1074 callEntityScriptMethod(entityID, "unload");
1075 _entityScripts.remove(entityID);1075 _entityScripts.remove(entityID);
@@ -1081,7 +1081,7 @@ void ScriptEngine::unloadAllEntityScripts() { · 5 unmodified lines
1081#ifdef THREAD_DEBUGGING1081#ifdef THREAD_DEBUGGING
1082 qDebug() << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";1082 qDebug() << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
1083#endif1083#endif
1084 1084
1085 QMetaObject::invokeMethod(this, "unloadAllEntityScripts");1085 QMetaObject::invokeMethod(this, "unloadAllEntityScripts");
1086 return;1086 return;
1087 }1087 }
@@ -1098,13 +1098,13 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 10 unmodified lines
1098 if (!_entityScripts.contains(entityID)) {1098 if (!_entityScripts.contains(entityID)) {
1099 return;1099 return;
1100 }1100 }
1101 1101
1102 static bool recurseGuard = false;1102 static bool recurseGuard = false;
1103 if (recurseGuard) {1103 if (recurseGuard) {
1104 return;1104 return;
1105 }1105 }
1106 recurseGuard = true;1106 recurseGuard = true;
1107 1107
1108 EntityScriptDetails details = _entityScripts[entityID];1108 EntityScriptDetails details = _entityScripts[entityID];
1109 // Check to see if a file based script needs to be reloaded (easier debugging)1109 // Check to see if a file based script needs to be reloaded (easier debugging)
1110 if (details.lastModified > 0) {1110 if (details.lastModified > 0) {
@@ -1112,7 +1112,7 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 1 unmodified line
1112 auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();1112 auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch();
1113 if (lastModified > details.lastModified) {1113 if (lastModified > details.lastModified) {
1114 qDebug() << "Reloading modified script " << details.scriptText;1114 qDebug() << "Reloading modified script " << details.scriptText;
1115 1115
1116 QFile file(filePath);1116 QFile file(filePath);
1117 file.open(QIODevice::ReadOnly);1117 file.open(QIODevice::ReadOnly);
1118 QString scriptContents = QTextStream(&file).readAll();1118 QString scriptContents = QTextStream(&file).readAll();
@@ -1131,21 +1131,21 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 12 unmodified lines
1131 1131
1132void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName) {1132void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName) {
1133 if (QThread::currentThread() != thread()) {1133 if (QThread::currentThread() != thread()) {
1134 #ifdef THREAD_DEBUGGING1134#ifdef THREAD_DEBUGGING
1135 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "1135 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
1136 "entityID:" << entityID << "methodName:" << methodName;1136 "entityID:" << entityID << "methodName:" << methodName;
1137 #endif1137#endif
1138 1138
1139 QMetaObject::invokeMethod(this, "callEntityScriptMethod",1139 QMetaObject::invokeMethod(this, "callEntityScriptMethod",
1140 Q_ARG(const EntityItemID&, entityID),1140 Q_ARG(const EntityItemID&, entityID),
1141 Q_ARG(const QString&, methodName));1141 Q_ARG(const QString&, methodName));
1142 return;1142 return;
1143 }1143 }
1144 #ifdef THREAD_DEBUGGING1144#ifdef THREAD_DEBUGGING
1145 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "1145 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
1146 "entityID:" << entityID << "methodName:" << methodName;1146 "entityID:" << entityID << "methodName:" << methodName;
1147 #endif1147#endif
1148 1148
1149 refreshFileScript(entityID);1149 refreshFileScript(entityID);
1150 if (_entityScripts.contains(entityID)) {1150 if (_entityScripts.contains(entityID)) {
1151 EntityScriptDetails details = _entityScripts[entityID];1151 EntityScriptDetails details = _entityScripts[entityID];
@@ -1155,28 +1155,28 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 3 unmodified lines
1155 args << entityID.toScriptValue(this);1155 args << entityID.toScriptValue(this);
1156 entityScript.property(methodName).call(entityScript, args);1156 entityScript.property(methodName).call(entityScript, args);
1157 }1157 }
1158 1158
1159 }1159 }
1160}1160}
1161 1161
1162void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event) {1162void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const MouseEvent& event) {
1163 if (QThread::currentThread() != thread()) {1163 if (QThread::currentThread() != thread()) {
1164 #ifdef THREAD_DEBUGGING1164#ifdef THREAD_DEBUGGING
1165 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "1165 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
1166 "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";1166 "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
1167 #endif1167#endif
1168 1168
1169 QMetaObject::invokeMethod(this, "callEntityScriptMethod",1169 QMetaObject::invokeMethod(this, "callEntityScriptMethod",
1170 Q_ARG(const EntityItemID&, entityID),1170 Q_ARG(const EntityItemID&, entityID),
1171 Q_ARG(const QString&, methodName),1171 Q_ARG(const QString&, methodName),
1172 Q_ARG(const MouseEvent&, event));1172 Q_ARG(const MouseEvent&, event));
1173 return;1173 return;
1174 }1174 }
1175 #ifdef THREAD_DEBUGGING1175#ifdef THREAD_DEBUGGING
1176 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "1176 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
1177 "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";1177 "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
1178 #endif1178#endif
1179 1179
1180 refreshFileScript(entityID);1180 refreshFileScript(entityID);
1181 if (_entityScripts.contains(entityID)) {1181 if (_entityScripts.contains(entityID)) {
1182 EntityScriptDetails details = _entityScripts[entityID];1182 EntityScriptDetails details = _entityScripts[entityID];
@@ -1193,23 +1193,23 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 10 unmodified lines
1193 1193
1194void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) {1194void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) {
1195 if (QThread::currentThread() != thread()) {1195 if (QThread::currentThread() != thread()) {
1196 #ifdef THREAD_DEBUGGING1196#ifdef THREAD_DEBUGGING
1197 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "1197 qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
1198 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";1198 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
1199 #endif1199#endif
1200 1200
1201 QMetaObject::invokeMethod(this, "callEntityScriptMethod",1201 QMetaObject::invokeMethod(this, "callEntityScriptMethod",
1202 Q_ARG(const EntityItemID&, entityID),1202 Q_ARG(const EntityItemID&, entityID),
1203 Q_ARG(const QString&, methodName),1203 Q_ARG(const QString&, methodName),
1204 Q_ARG(const EntityItemID&, otherID),1204 Q_ARG(const EntityItemID&, otherID),
1205 Q_ARG(const Collision&, collision));1205 Q_ARG(const Collision&, collision));
1206 return;1206 return;
1207 }1207 }
1208 #ifdef THREAD_DEBUGGING1208#ifdef THREAD_DEBUGGING
1209 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "1209 qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] "
1210 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";1210 "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
1211 #endif1211#endif
1212 1212
1213 refreshFileScript(entityID);1213 refreshFileScript(entityID);
1214 if (_entityScripts.contains(entityID)) {1214 if (_entityScripts.contains(entityID)) {
1215 EntityScriptDetails details = _entityScripts[entityID];1215 EntityScriptDetails details = _entityScripts[entityID];
@@ -1222,4 +1222,4 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 6 unmodified lines
1222 entityScript.property(methodName).call(entityScript, args);1222 entityScript.property(methodName).call(entityScript, args);
1223 }1223 }
1224 }1224 }
1225}1225}