Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 325 files). Show all
Unified · Split
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | #include <AudioEffectOptions.h> | 24 | #include <AudioEffectOptions.h> |
| 25 | #include <AvatarData.h> | 25 | #include <AvatarData.h> |
| 26 | #include <EntityScriptingInterface.h> | 26 | #include <EntityScriptingInterface.h> |
| 27 | #include <MessagesClient.h> | ||
| 27 | #include <NetworkAccessManager.h> | 28 | #include <NetworkAccessManager.h> |
| 28 | #include <NodeList.h> | 29 | #include <NodeList.h> |
| 29 | #include <udt/PacketHeaders.h> | 30 | #include <udt/PacketHeaders.h> |
| @@ -46,6 +47,7 @@ · 16 unmodified lines | |||
| 46 | #include "WebSocketClass.h" | 47 | #include "WebSocketClass.h" |
| 47 | 48 | ||
| 48 | #include "SceneScriptingInterface.h" | 49 | #include "SceneScriptingInterface.h" |
| 50 | #include "RecordingScriptingInterface.h" | ||
| 49 | 51 | ||
| 50 | #include "MIDIEvent.h" | 52 | #include "MIDIEvent.h" |
| 51 | 53 | ||
| @@ -60,14 +62,14 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ · 8 unmodified lines | |||
| 60 | } | 62 | } |
| 61 | message += context->argument(i).toString(); | 63 | message += context->argument(i).toString(); |
| 62 | } | 64 | } |
| 63 | qCDebug(scriptengine) << "script:print()<<" << message; | 65 | qCDebug(scriptengine).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline |
| 64 | 66 | ||
| 65 | message = message.replace("\\", "\\\\") | 67 | message = message.replace("\\", "\\\\") |
| 66 | .replace("\n", "\\n") | 68 | .replace("\n", "\\n") |
| 67 | .replace("\r", "\\r") | 69 | .replace("\r", "\\r") |
| 68 | .replace("'", "\\'"); | 70 | .replace("'", "\\'"); |
| 69 | engine->evaluate("Script.print('" + message + "')"); | 71 | engine->evaluate("Script.print('" + message + "')"); |
| 70 | 72 | ||
| 71 | return QScriptValue(); | 73 | return QScriptValue(); |
| 72 | } | 74 | } |
| 73 | 75 | ||
| @@ -108,7 +110,7 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName · 34 unmodified lines | |||
| 108 | const auto exception = engine.uncaughtException().toString(); | 110 | const auto exception = engine.uncaughtException().toString(); |
| 109 | const auto line = QString::number(engine.uncaughtExceptionLineNumber()); | 111 | const auto line = QString::number(engine.uncaughtExceptionLineNumber()); |
| 110 | engine.clearExceptions(); | 112 | engine.clearExceptions(); |
| 111 | 113 | ||
| 112 | auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); | 114 | auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); |
| 113 | if (!backtrace.empty()) { | 115 | if (!backtrace.empty()) { |
| 114 | static const auto lineSeparator = "\n "; | 116 | static const auto lineSeparator = "\n "; |
| @@ -121,16 +123,11 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName · 6 unmodified lines | |||
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) : | 125 | ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) : |
| 124 | _scriptContents(scriptContents), | 126 | _scriptContents(scriptContents), |
| 125 | _isFinished(false), | 127 | _timerFunctionMap(), |
| 126 | _isRunning(false), | 128 | _wantSignals(wantSignals), |
| 127 | _isInitialized(false), | 129 | _fileNameString(fileNameString), |
| 128 | _timerFunctionMap(), | 130 | _arrayBufferClass(new ArrayBufferClass(this)) |
| 129 | _wantSignals(wantSignals), | ||
| 130 | _fileNameString(fileNameString), | ||
| 131 | _isUserLoaded(false), | ||
| 132 | _isReloading(false), | ||
| 133 | _arrayBufferClass(new ArrayBufferClass(this)) | ||
| 134 | { | 131 | { |
| 135 | _allScriptsMutex.lock(); | 132 | _allScriptsMutex.lock(); |
| 136 | _allKnownScriptEngines.insert(this); | 133 | _allKnownScriptEngines.insert(this); |
| @@ -138,6 +135,8 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 1 unmodified line | |||
| 138 | } | 135 | } |
| 139 | 136 | ||
| 140 | ScriptEngine::~ScriptEngine() { | 137 | ScriptEngine::~ScriptEngine() { |
| 138 | qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename(); | ||
| 139 | |||
| 141 | // If we're not already in the middle of stopping all scripts, then we should remove ourselves | 140 | // If we're not already in the middle of stopping all scripts, then we should remove ourselves |
| 142 | // from the list of running scripts. We don't do this if we're in the process of stopping all scripts | 141 | // from the list of running scripts. We don't do this if we're in the process of stopping all scripts |
| 143 | // because that method removes scripts from its list as it iterates them | 142 | // because that method removes scripts from its list as it iterates them |
| @@ -148,25 +147,35 @@ ScriptEngine::~ScriptEngine() { · 4 unmodified lines | |||
| 148 | } | 147 | } |
| 149 | } | 148 | } |
| 150 | 149 | ||
| 150 | void ScriptEngine::disconnectNonEssentialSignals() { | ||
| 151 | disconnect(); | ||
| 152 | connect(this, &ScriptEngine::doneRunning, thread(), &QThread::quit); | ||
| 153 | } | ||
| 154 | |||
| 151 | void ScriptEngine::runInThread() { | 155 | void ScriptEngine::runInThread() { |
| 156 | _isThreaded = true; | ||
| 152 | QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete | 157 | QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete |
| 153 | QString scriptEngineName = QString("Script Thread:") + getFilename(); | 158 | QString scriptEngineName = QString("Script Thread:") + getFilename(); |
| 154 | workerThread->setObjectName(scriptEngineName); | 159 | workerThread->setObjectName(scriptEngineName); |
| 155 | 160 | ||
| 161 | // NOTE: If you connect any essential signals for proper shutdown or cleanup of | ||
| 162 | // the script engine, make sure to add code to "reconnect" them to the | ||
| 163 | // disconnectNonEssentialSignals() method | ||
| 164 | |||
| 156 | // when the worker thread is started, call our engine's run.. | 165 | // when the worker thread is started, call our engine's run.. |
| 157 | connect(workerThread, &QThread::started, this, &ScriptEngine::run); | 166 | connect(workerThread, &QThread::started, this, &ScriptEngine::run); |
| 158 | 167 | ||
| 159 | // tell the thread to stop when the script engine is done | 168 | // tell the thread to stop when the script engine is done |
| 160 | connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); | 169 | connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); |
| 161 | 170 | ||
| 162 | // when the thread is finished, add thread to the deleteLater queue | 171 | // when the thread is finished, add thread to the deleteLater queue |
| 163 | connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); | 172 | connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); |
| 164 | 173 | ||
| 165 | // when the thread is finished, add scriptEngine to the deleteLater queue | 174 | // when the thread is finished, add scriptEngine to the deleteLater queue |
| 166 | connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater); | 175 | connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater); |
| 167 | 176 | ||
| 168 | moveToThread(workerThread); | 177 | moveToThread(workerThread); |
| 169 | 178 | ||
| 170 | // Starts an event loop, and emits workerThread->started() | 179 | // Starts an event loop, and emits workerThread->started() |
| 171 | workerThread->start(); | 180 | workerThread->start(); |
| 172 | } | 181 | } |
| @@ -174,28 +183,29 @@ void ScriptEngine::runInThread() { · 1 unmodified line | |||
| 174 | QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines; | 183 | QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines; |
| 175 | QMutex ScriptEngine::_allScriptsMutex; | 184 | QMutex ScriptEngine::_allScriptsMutex; |
| 176 | bool ScriptEngine::_stoppingAllScripts = false; | 185 | bool ScriptEngine::_stoppingAllScripts = false; |
| 177 | bool ScriptEngine::_doneRunningThisScript = false; | ||
| 178 | 186 | ||
| 179 | void ScriptEngine::stopAllScripts(QObject* application) { | 187 | void ScriptEngine::stopAllScripts(QObject* application) { |
| 180 | _allScriptsMutex.lock(); | 188 | _allScriptsMutex.lock(); |
| 181 | _stoppingAllScripts = true; | 189 | _stoppingAllScripts = true; |
| 182 | 190 | ||
| 191 | qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size(); | ||
| 192 | |||
| 183 | QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines); | 193 | QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines); |
| 184 | while (i.hasNext()) { | 194 | while (i.hasNext()) { |
| 185 | ScriptEngine* scriptEngine = i.next(); | 195 | ScriptEngine* scriptEngine = i.next(); |
| 186 | 196 | ||
| 187 | QString scriptName = scriptEngine->getFilename(); | 197 | QString scriptName = scriptEngine->getFilename(); |
| 188 | 198 | ||
| 189 | // NOTE: typically all script engines are running. But there's at least one known exception to this, the | 199 | // NOTE: typically all script engines are running. But there's at least one known exception to this, the |
| 190 | // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using | 200 | // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using |
| 191 | // them. We don't need to stop scripts that aren't running. | 201 | // them. We don't need to stop scripts that aren't running. |
| 192 | if (scriptEngine->isRunning()) { | 202 | if (scriptEngine->isRunning()) { |
| 193 | 203 | ||
| 194 | // If the script is running, but still evaluating then we need to wait for its evaluation step to | 204 | // If the script is running, but still evaluating then we need to wait for its evaluation step to |
| 195 | // complete. After that we can handle the stop process appropriately | 205 | // complete. After that we can handle the stop process appropriately |
| 196 | if (scriptEngine->evaluatePending()) { | 206 | if (scriptEngine->evaluatePending()) { |
| 197 | while (scriptEngine->evaluatePending()) { | 207 | while (scriptEngine->evaluatePending()) { |
| 198 | 208 | ||
| 199 | // This event loop allows any started, but not yet finished evaluate() calls to complete | 209 | // This event loop allows any started, but not yet finished evaluate() calls to complete |
| 200 | // we need to let these complete so that we can be guaranteed that the script engine isn't | 210 | // we need to let these complete so that we can be guaranteed that the script engine isn't |
| 201 | // in a partially setup state, which can confuse our shutdown unwinding. | 211 | // in a partially setup state, which can confuse our shutdown unwinding. |
| @@ -204,42 +214,42 @@ void ScriptEngine::stopAllScripts(QObject* application) { · 2 unmodified lines | |||
| 204 | loop.exec(); | 214 | loop.exec(); |
| 205 | } | 215 | } |
| 206 | } | 216 | } |
| 207 | 217 | ||
| 208 | // We disconnect any script engine signals from the application because we don't want to do any | 218 | // We disconnect any script engine signals from the application because we don't want to do any |
| 209 | // extra stopScript/loadScript processing that the Application normally does when scripts start | 219 | // extra stopScript/loadScript processing that the Application normally does when scripts start |
| 210 | // and stop. We can safely short circuit this because we know we're in the "quitting" process | 220 | // and stop. We can safely short circuit this because we know we're in the "quitting" process |
| 211 | scriptEngine->disconnect(application); | 221 | scriptEngine->disconnect(application); |
| 212 | 222 | ||
| 213 | // Calling stop on the script engine will set it's internal _isFinished state to true, and result | 223 | // Calling stop on the script engine will set it's internal _isFinished state to true, and result |
| 214 | // in the ScriptEngine gracefully ending it's run() method. | 224 | // in the ScriptEngine gracefully ending it's run() method. |
| 215 | scriptEngine->stop(); | 225 | scriptEngine->stop(); |
| 216 | 226 | ||
| 217 | // We need to wait for the engine to be done running before we proceed, because we don't | 227 | // We need to wait for the engine to be done running before we proceed, because we don't |
| 218 | // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing | 228 | // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing |
| 219 | // any application state after we leave this stopAllScripts() method | 229 | // any application state after we leave this stopAllScripts() method |
| 230 | qCDebug(scriptengine) << "waiting on script:" << scriptName; | ||
| 220 | scriptEngine->waitTillDoneRunning(); | 231 | scriptEngine->waitTillDoneRunning(); |
| 221 | 232 | qCDebug(scriptengine) << "done waiting on script:" << scriptName; | |
| 233 | |||
| 222 | // If the script is stopped, we can remove it from our set | 234 | // If the script is stopped, we can remove it from our set |
| 223 | i.remove(); | 235 | i.remove(); |
| 224 | } | 236 | } |
| 225 | } | 237 | } |
| 226 | _stoppingAllScripts = false; | 238 | _stoppingAllScripts = false; |
| 227 | _allScriptsMutex.unlock(); | 239 | _allScriptsMutex.unlock(); |
| 240 | qCDebug(scriptengine) << "DONE Stopping all scripts...."; | ||
| 228 | } | 241 | } |
| 229 | 242 | ||
| 230 | 243 | ||
| 231 | void ScriptEngine::waitTillDoneRunning() { | 244 | void ScriptEngine::waitTillDoneRunning() { |
| 232 | // If the script never started running or finished running before we got here, we don't need to wait for it | 245 | // If the script never started running or finished running before we got here, we don't need to wait for it |
| 233 | if (_isRunning) { | 246 | if (_isRunning && _isThreaded) { |
| 234 | 247 | ||
| 235 | _doneRunningThisScript = false; // NOTE: this is static, we serialize our waiting for scripts to finish | ||
| 236 | |||
| 237 | // NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts() | 248 | // NOTE: waitTillDoneRunning() will be called on the main Application thread, inside of stopAllScripts() |
| 238 | // we want the application thread to continue to process events, because the scripts will likely need to | 249 | // we want the application thread to continue to process events, because the scripts will likely need to |
| 239 | // marshall messages across to the main thread. For example if they access Settings or Meny in any of their | 250 | // marshall messages across to the main thread. For example if they access Settings or Meny in any of their |
| 240 | // shutdown code. | 251 | // shutdown code. |
| 241 | while (!_doneRunningThisScript) { | 252 | while (thread()->isRunning()) { |
| 242 | |||
| 243 | // process events for the main application thread, allowing invokeMethod calls to pass between threads | 253 | // process events for the main application thread, allowing invokeMethod calls to pass between threads |
| 244 | QCoreApplication::processEvents(); | 254 | QCoreApplication::processEvents(); |
| 245 | } | 255 | } |
| @@ -261,12 +271,12 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { · 15 unmodified lines | |||
| 261 | if (_isRunning) { | 271 | if (_isRunning) { |
| 262 | return; | 272 | return; |
| 263 | } | 273 | } |
| 264 | 274 | ||
| 265 | _fileNameString = scriptURL.toString(); | 275 | _fileNameString = scriptURL.toString(); |
| 266 | _isReloading = reload; | 276 | _isReloading = reload; |
| 267 | 277 | ||
| 268 | QUrl url(scriptURL); | 278 | QUrl url(scriptURL); |
| 269 | 279 | ||
| 270 | bool isPending; | 280 | bool isPending; |
| 271 | auto scriptCache = DependencyManager::get<ScriptCache>(); | 281 | auto scriptCache = DependencyManager::get<ScriptCache>(); |
| 272 | scriptCache->getScript(url, this, isPending, reload); | 282 | scriptCache->getScript(url, this, isPending, reload); |
| @@ -313,12 +323,12 @@ void ScriptEngine::init() { · 40 unmodified lines | |||
| 313 | if (_isInitialized) { | 323 | if (_isInitialized) { |
| 314 | return; // only initialize once | 324 | return; // only initialize once |
| 315 | } | 325 | } |
| 316 | 326 | ||
| 317 | _isInitialized = true; | 327 | _isInitialized = true; |
| 318 | 328 | ||
| 319 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | 329 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 320 | entityScriptingInterface->init(); | 330 | entityScriptingInterface->init(); |
| 321 | 331 | ||
| 322 | // register various meta-types | 332 | // register various meta-types |
| 323 | registerMetaTypes(this); | 333 | registerMetaTypes(this); |
| 324 | registerMIDIMetaTypes(this); | 334 | registerMIDIMetaTypes(this); |
| @@ -327,30 +337,30 @@ void ScriptEngine::init() { · 2 unmodified lines | |||
| 327 | registerAnimationTypes(this); | 337 | registerAnimationTypes(this); |
| 328 | registerAvatarTypes(this); | 338 | registerAvatarTypes(this); |
| 329 | registerAudioMetaTypes(this); | 339 | registerAudioMetaTypes(this); |
| 330 | 340 | ||
| 331 | qScriptRegisterMetaType(this, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue); | 341 | qScriptRegisterMetaType(this, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue); |
| 332 | qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); | 342 | qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); |
| 333 | qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); | 343 | qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); |
| 334 | qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); | 344 | qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); |
| 335 | qScriptRegisterSequenceMetaType<QVector<QUuid>>(this); | 345 | qScriptRegisterSequenceMetaType<QVector<QUuid>>(this); |
| 336 | qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this); | 346 | qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this); |
| 337 | 347 | ||
| 338 | qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this); | 348 | qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this); |
| 339 | qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this); | 349 | qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this); |
| 340 | qScriptRegisterSequenceMetaType<QVector<QString> >(this); | 350 | qScriptRegisterSequenceMetaType<QVector<QString> >(this); |
| 341 | 351 | ||
| 342 | QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); | 352 | QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); |
| 343 | globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); | 353 | globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); |
| 344 | 354 | ||
| 345 | QScriptValue webSocketConstructorValue = newFunction(WebSocketClass::constructor); | 355 | QScriptValue webSocketConstructorValue = newFunction(WebSocketClass::constructor); |
| 346 | globalObject().setProperty("WebSocket", webSocketConstructorValue); | 356 | globalObject().setProperty("WebSocket", webSocketConstructorValue); |
| 347 | 357 | ||
| 348 | QScriptValue printConstructorValue = newFunction(debugPrint); | 358 | QScriptValue printConstructorValue = newFunction(debugPrint); |
| 349 | globalObject().setProperty("print", printConstructorValue); | 359 | globalObject().setProperty("print", printConstructorValue); |
| 350 | 360 | ||
| 351 | QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); | 361 | QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); |
| 352 | globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); | 362 | globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); |
| 353 | 363 | ||
| 354 | qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); | 364 | qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); |
| 355 | qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); | 365 | qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); |
| 356 | qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue); | 366 | qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue); |
| @@ -358,7 +368,7 @@ void ScriptEngine::init() { · 1 unmodified line | |||
| 358 | qScriptRegisterMetaType(this, webSocketToScriptValue, webSocketFromScriptValue); | 368 | qScriptRegisterMetaType(this, webSocketToScriptValue, webSocketFromScriptValue); |
| 359 | qScriptRegisterMetaType(this, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue); | 369 | qScriptRegisterMetaType(this, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue); |
| 360 | qScriptRegisterMetaType(this, wscReadyStateToScriptValue, wscReadyStateFromScriptValue); | 370 | qScriptRegisterMetaType(this, wscReadyStateToScriptValue, wscReadyStateFromScriptValue); |
| 361 | 371 | ||
| 362 | registerGlobalObject("Script", this); | 372 | registerGlobalObject("Script", this); |
| 363 | registerGlobalObject("Audio", &AudioScriptingInterface::getInstance()); | 373 | registerGlobalObject("Audio", &AudioScriptingInterface::getInstance()); |
| 364 | registerGlobalObject("Entities", entityScriptingInterface.data()); | 374 | registerGlobalObject("Entities", entityScriptingInterface.data()); |
| @@ -366,15 +376,22 @@ void ScriptEngine::init() { · 1 unmodified line | |||
| 366 | registerGlobalObject("Vec3", &_vec3Library); | 376 | registerGlobalObject("Vec3", &_vec3Library); |
| 367 | registerGlobalObject("Uuid", &_uuidLibrary); | 377 | registerGlobalObject("Uuid", &_uuidLibrary); |
| 368 | registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data()); | 378 | registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data()); |
| 379 | registerGlobalObject("Messages", DependencyManager::get<MessagesClient>().data()); | ||
| 369 | qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue); | 380 | qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue); |
| 370 | qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue); | 381 | qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue); |
| 371 | 382 | ||
| 372 | // constants | 383 | // constants |
| 373 | globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); | 384 | globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); |
| 374 | 385 | ||
| 375 | auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>(); | 386 | auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>(); |
| 376 | registerGlobalObject("Controller", scriptingInterface.data()); | 387 | registerGlobalObject("Controller", scriptingInterface.data()); |
| 377 | UserInputMapper::registerControllerTypes(this); | 388 | UserInputMapper::registerControllerTypes(this); |
| 389 | |||
| 390 | auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>(); | ||
| 391 | registerGlobalObject("Recording", recordingInterface.data()); | ||
| 392 | |||
| 393 | registerGlobalObject("Assets", &_assetScriptingInterface); | ||
| 394 | |||
| 378 | } | 395 | } |
| 379 | 396 | ||
| 380 | void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { | 397 | void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { |
| @@ -387,11 +404,11 @@ void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { · 6 unmodified lines | |||
| 387 | Q_ARG(QScriptValue, value)); | 404 | Q_ARG(QScriptValue, value)); |
| 388 | return; | 405 | return; |
| 389 | } | 406 | } |
| 390 | 407 | ||
| 391 | QStringList pathToValue = valueName.split("."); | 408 | QStringList pathToValue = valueName.split("."); |
| 392 | int partsToGo = pathToValue.length(); | 409 | int partsToGo = pathToValue.length(); |
| 393 | QScriptValue partObject = globalObject(); | 410 | QScriptValue partObject = globalObject(); |
| 394 | 411 | ||
| 395 | for (const auto& pathPart : pathToValue) { | 412 | for (const auto& pathPart : pathToValue) { |
| 396 | partsToGo--; | 413 | partsToGo--; |
| 397 | if (!partObject.property(pathPart).isValid()) { | 414 | if (!partObject.property(pathPart).isValid()) { |
| @@ -421,7 +438,7 @@ void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { · 23 unmodified lines | |||
| 421 | #ifdef THREAD_DEBUGGING | 438 | #ifdef THREAD_DEBUGGING |
| 422 | qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; | 439 | qDebug() << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; |
| 423 | #endif | 440 | #endif |
| 424 | 441 | ||
| 425 | if (!globalObject().property(name).isValid()) { | 442 | if (!globalObject().property(name).isValid()) { |
| 426 | if (object) { | 443 | if (object) { |
| 427 | QScriptValue value = newQObject(object); | 444 | QScriptValue value = newQObject(object); |
| @@ -446,7 +463,7 @@ void ScriptEngine::registerFunction(const QString& name, QScriptEngine::Function · 18 unmodified lines | |||
| 446 | #ifdef THREAD_DEBUGGING | 463 | #ifdef THREAD_DEBUGGING |
| 447 | qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; | 464 | qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; |
| 448 | #endif | 465 | #endif |
| 449 | 466 | ||
| 450 | QScriptValue scriptFun = newFunction(functionSignature, numArguments); | 467 | QScriptValue scriptFun = newFunction(functionSignature, numArguments); |
| 451 | globalObject().setProperty(name, scriptFun); | 468 | globalObject().setProperty(name, scriptFun); |
| 452 | } | 469 | } |
| @@ -465,7 +482,7 @@ void ScriptEngine::registerFunction(const QString& parent, const QString& name, · 12 unmodified lines | |||
| 465 | #ifdef THREAD_DEBUGGING | 482 | #ifdef THREAD_DEBUGGING |
| 466 | qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; | 483 | qDebug() << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; |
| 467 | #endif | 484 | #endif |
| 468 | 485 | ||
| 469 | QScriptValue object = globalObject().property(parent); | 486 | QScriptValue object = globalObject().property(parent); |
| 470 | if (object.isValid()) { | 487 | if (object.isValid()) { |
| 471 | QScriptValue scriptFun = newFunction(functionSignature, numArguments); | 488 | QScriptValue scriptFun = newFunction(functionSignature, numArguments); |
| @@ -490,10 +507,10 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 18 unmodified lines | |||
| 490 | #ifdef THREAD_DEBUGGING | 507 | #ifdef THREAD_DEBUGGING |
| 491 | qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; | 508 | qDebug() << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; |
| 492 | #endif | 509 | #endif |
| 493 | 510 | ||
| 494 | QScriptValue setterFunction = newFunction(setter, 1); | 511 | QScriptValue setterFunction = newFunction(setter, 1); |
| 495 | QScriptValue getterFunction = newFunction(getter); | 512 | QScriptValue getterFunction = newFunction(getter); |
| 496 | 513 | ||
| 497 | if (!parent.isNull() && !parent.isEmpty()) { | 514 | if (!parent.isNull() && !parent.isEmpty()) { |
| 498 | QScriptValue object = globalObject().property(parent); | 515 | QScriptValue object = globalObject().property(parent); |
| 499 | if (object.isValid()) { | 516 | if (object.isValid()) { |
| @@ -522,7 +539,7 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin · 22 unmodified lines | |||
| 522 | #ifdef THREAD_DEBUGGING | 539 | #ifdef THREAD_DEBUGGING |
| 523 | qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; | 540 | qDebug() << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; |
| 524 | #endif | 541 | #endif |
| 525 | 542 | ||
| 526 | if (!_registeredHandlers.contains(entityID)) { | 543 | if (!_registeredHandlers.contains(entityID)) { |
| 527 | return; | 544 | return; |
| 528 | } | 545 | } |
| @@ -543,7 +560,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 14 unmodified lines | |||
| 543 | qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | 560 | qDebug() << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " |
| 544 | "entityID:" << entityID << " eventName:" << eventName; | 561 | "entityID:" << entityID << " eventName:" << eventName; |
| 545 | #endif | 562 | #endif |
| 546 | 563 | ||
| 547 | QMetaObject::invokeMethod(this, "addEventHandler", | 564 | QMetaObject::invokeMethod(this, "addEventHandler", |
| 548 | Q_ARG(const EntityItemID&, entityID), | 565 | Q_ARG(const EntityItemID&, entityID), |
| 549 | Q_ARG(const QString&, eventName), | 566 | Q_ARG(const QString&, eventName), |
| @@ -553,7 +570,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 3 unmodified lines | |||
| 553 | #ifdef THREAD_DEBUGGING | 570 | #ifdef THREAD_DEBUGGING |
| 554 | qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; | 571 | qDebug() << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; |
| 555 | #endif | 572 | #endif |
| 556 | 573 | ||
| 557 | if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script... | 574 | if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script... |
| 558 | // Connect up ALL the handlers to the global entities object's signals. | 575 | // Connect up ALL the handlers to the global entities object's signals. |
| 559 | // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) | 576 | // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) |
| @@ -561,7 +578,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 1 unmodified line | |||
| 561 | connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { | 578 | connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { |
| 562 | _registeredHandlers.remove(entityID); | 579 | _registeredHandlers.remove(entityID); |
| 563 | }); | 580 | }); |
| 564 | 581 | ||
| 565 | // Two common cases of event handler, differing only in argument signature. | 582 | // Two common cases of event handler, differing only in argument signature. |
| 566 | using SingleEntityHandler = std::function<void(const EntityItemID&)>; | 583 | using SingleEntityHandler = std::function<void(const EntityItemID&)>; |
| 567 | auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler { | 584 | auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler { |
| @@ -569,37 +586,37 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& · 1 unmodified line | |||
| 569 | forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); | 586 | forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); |
| 570 | }; | 587 | }; |
| 571 | }; | 588 | }; |
| 572 | 589 | ||
| 573 | using MouseHandler = std::function<void(const EntityItemID&, const MouseEvent&)>; | 590 | using MouseHandler = std::function<void(const EntityItemID&, const MouseEvent&)>; |
| 574 | auto makeMouseHandler = [this](QString eventName) -> MouseHandler { | 591 | auto makeMouseHandler = [this](QString eventName) -> MouseHandler { |
| 575 | return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) { | 592 | return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) { |
| 576 | forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); | 593 | forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); |
| 577 | }; | 594 | }; |
| 578 | }; | 595 | }; |
| 579 | 596 | ||
| 580 | using CollisionHandler = std::function<void(const EntityItemID&, const EntityItemID&, const Collision&)>; | 597 | using CollisionHandler = std::function<void(const EntityItemID&, const EntityItemID&, const Collision&)>; |
| 581 | auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { | 598 | auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { |
| 582 | return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { | 599 | return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { |
| 583 | forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), | 600 | forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), |
| 584 | collisionToScriptValue(this, collision) }); | 601 | collisionToScriptValue(this, collision) }); |
| 585 | }; | 602 | }; |
| 586 | }; | 603 | }; |
| 587 | 604 | ||
| 588 | connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); | 605 | connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); |
| 589 | connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); | 606 | connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); |
| 590 | 607 | ||
| 591 | connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity")); | 608 | connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity")); |
| 592 | connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity")); | 609 | connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity")); |
| 593 | connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity")); | 610 | connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity")); |
| 594 | 611 | ||
| 595 | connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity")); | 612 | connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity")); |
| 596 | connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity")); | 613 | connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity")); |
| 597 | connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity")); | 614 | connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity")); |
| 598 | 615 | ||
| 599 | connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity")); | 616 | connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity")); |
| 600 | connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity")); | 617 | connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity")); |
| 601 | connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity")); | 618 | connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity")); |
| 602 | 619 | ||
| 603 | connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity")); | 620 | connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity")); |
| 604 | } | 621 | } |
| 605 | if (!_registeredHandlers.contains(entityID)) { | 622 | if (!_registeredHandlers.contains(entityID)) { |
| @@ -614,7 +631,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 8 unmodified lines | |||
| 614 | if (_stoppingAllScripts) { | 631 | if (_stoppingAllScripts) { |
| 615 | return QScriptValue(); // bail early | 632 | return QScriptValue(); // bail early |
| 616 | } | 633 | } |
| 617 | 634 | ||
| 618 | if (QThread::currentThread() != thread()) { | 635 | if (QThread::currentThread() != thread()) { |
| 619 | QScriptValue result; | 636 | QScriptValue result; |
| 620 | #ifdef THREAD_DEBUGGING | 637 | #ifdef THREAD_DEBUGGING |
| @@ -628,17 +645,17 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi · 7 unmodified lines | |||
| 628 | Q_ARG(int, lineNumber)); | 645 | Q_ARG(int, lineNumber)); |
| 629 | return result; | 646 | return result; |
| 630 | } | 647 | } |
| 631 | 648 | ||
| 632 | // Check syntax | 649 | // Check syntax |
| 633 | const QScriptProgram program(sourceCode, fileName, lineNumber); | 650 | const QScriptProgram program(sourceCode, fileName, lineNumber); |
| 634 | if (!hasCorrectSyntax(program)) { | 651 | if (!hasCorrectSyntax(program)) { |
| 635 | return QScriptValue(); | 652 | return QScriptValue(); |
| 636 | } | 653 | } |
| 637 | 654 | ||
| 638 | ++_evaluatesPending; | 655 | ++_evaluatesPending; |
| 639 | const auto result = QScriptEngine::evaluate(program); | 656 | const auto result = QScriptEngine::evaluate(program); |
| 640 | --_evaluatesPending; | 657 | --_evaluatesPending; |
| 641 | 658 | ||
| 642 | const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName()); | 659 | const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName()); |
| 643 | if (_wantSignals) { | 660 | if (_wantSignals) { |
| 644 | emit evaluationFinished(result, hadUncaughtException); | 661 | emit evaluationFinished(result, hadUncaughtException); |
| @@ -650,7 +667,7 @@ void ScriptEngine::run() { · 5 unmodified lines | |||
| 650 | if (_stoppingAllScripts) { | 667 | if (_stoppingAllScripts) { |
| 651 | return; // bail early - avoid setting state in init(), as evaluate() will bail too | 668 | return; // bail early - avoid setting state in init(), as evaluate() will bail too |
| 652 | } | 669 | } |
| 653 | 670 | ||
| 654 | if (!_isInitialized) { | 671 | if (!_isInitialized) { |
| 655 | init(); | 672 | init(); |
| 656 | } | 673 | } |
| @@ -660,68 +677,68 @@ void ScriptEngine::run() { · 3 unmodified lines | |||
| 660 | if (_wantSignals) { | 677 | if (_wantSignals) { |
| 661 | emit runningStateChanged(); | 678 | emit runningStateChanged(); |
| 662 | } | 679 | } |
| 663 | 680 | ||
| 664 | QScriptValue result = evaluate(_scriptContents, _fileNameString); | 681 | QScriptValue result = evaluate(_scriptContents, _fileNameString); |
| 665 | 682 | ||
| 666 | QElapsedTimer startTime; | 683 | QElapsedTimer startTime; |
| 667 | startTime.start(); | 684 | startTime.start(); |
| 668 | 685 | ||
| 669 | int thisFrame = 0; | 686 | int thisFrame = 0; |
| 670 | 687 | ||
| 671 | auto nodeList = DependencyManager::get<NodeList>(); | 688 | auto nodeList = DependencyManager::get<NodeList>(); |
| 672 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | 689 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 673 | 690 | ||
| 674 | qint64 lastUpdate = usecTimestampNow(); | 691 | qint64 lastUpdate = usecTimestampNow(); |
| 675 | 692 | ||
| 676 | while (!_isFinished) { | 693 | while (!_isFinished) { |
| 677 | int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec | 694 | int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec |
| 678 | if (usecToSleep > 0) { | 695 | if (usecToSleep > 0) { |
| 679 | usleep(usecToSleep); | 696 | usleep(usecToSleep); |
| 680 | } | 697 | } |
| 681 | 698 | ||
| 682 | if (_isFinished) { | 699 | if (_isFinished) { |
| 683 | break; | 700 | break; |
| 684 | } | 701 | } |
| 685 | 702 | ||
| 686 | QCoreApplication::processEvents(); | 703 | QCoreApplication::processEvents(); |
| 687 | 704 | ||
| 688 | if (_isFinished) { | 705 | if (_isFinished) { |
| 689 | break; | 706 | break; |
| 690 | } | 707 | } |
| 691 | 708 | ||
| 692 | if (!_isFinished && entityScriptingInterface->getEntityPacketSender()->serversExist()) { | 709 | if (!_isFinished && entityScriptingInterface->getEntityPacketSender()->serversExist()) { |
| 693 | // release the queue of edit entity messages. | 710 | // release the queue of edit entity messages. |
| 694 | entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); | 711 | entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); |
| 695 | 712 | ||
| 696 | // since we're in non-threaded mode, call process so that the packets are sent | 713 | // since we're in non-threaded mode, call process so that the packets are sent |
| 697 | if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) { | 714 | if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) { |
| 698 | entityScriptingInterface->getEntityPacketSender()->process(); | 715 | entityScriptingInterface->getEntityPacketSender()->process(); |
| 699 | } | 716 | } |
| 700 | } | 717 | } |
| 701 | 718 | ||
| 702 | qint64 now = usecTimestampNow(); | 719 | qint64 now = usecTimestampNow(); |
| 703 | float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; | 720 | float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; |
| 704 | 721 | ||
| 705 | if (!_isFinished) { | 722 | if (!_isFinished) { |
| 706 | if (_wantSignals) { | 723 | if (_wantSignals) { |
| 707 | emit update(deltaTime); | 724 | emit update(deltaTime); |
| 708 | } | 725 | } |
| 709 | } | 726 | } |
| 710 | lastUpdate = now; | 727 | lastUpdate = now; |
| 711 | 728 | ||
| 712 | // Debug and clear exceptions | 729 | // Debug and clear exceptions |
| 713 | hadUncaughtExceptions(*this, _fileNameString); | 730 | hadUncaughtExceptions(*this, _fileNameString); |
| 714 | } | 731 | } |
| 715 | 732 | ||
| 716 | stopAllTimers(); // make sure all our timers are stopped if the script is ending | 733 | stopAllTimers(); // make sure all our timers are stopped if the script is ending |
| 717 | if (_wantSignals) { | 734 | if (_wantSignals) { |
| 718 | emit scriptEnding(); | 735 | emit scriptEnding(); |
| 719 | } | 736 | } |
| 720 | 737 | ||
| 721 | if (entityScriptingInterface->getEntityPacketSender()->serversExist()) { | 738 | if (entityScriptingInterface->getEntityPacketSender()->serversExist()) { |
| 722 | // release the queue of edit entity messages. | 739 | // release the queue of edit entity messages. |
| 723 | entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); | 740 | entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); |
| 724 | 741 | ||
| 725 | // since we're in non-threaded mode, call process so that the packets are sent | 742 | // since we're in non-threaded mode, call process so that the packets are sent |
| 726 | if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) { | 743 | if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) { |
| 727 | // wait here till the edit packet sender is completely done sending | 744 | // wait here till the edit packet sender is completely done sending |
| @@ -733,18 +750,16 @@ void ScriptEngine::run() { · 5 unmodified lines | |||
| 733 | // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders? | 750 | // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders? |
| 734 | } | 751 | } |
| 735 | } | 752 | } |
| 736 | 753 | ||
| 737 | if (_wantSignals) { | 754 | if (_wantSignals) { |
| 738 | emit finished(_fileNameString); | 755 | emit finished(_fileNameString); |
| 739 | } | 756 | } |
| 740 | 757 | ||
| 741 | _isRunning = false; | 758 | _isRunning = false; |
| 742 | if (_wantSignals) { | 759 | if (_wantSignals) { |
| 743 | emit runningStateChanged(); | 760 | emit runningStateChanged(); |
| 744 | emit doneRunning(); | 761 | emit doneRunning(); |
| 745 | } | 762 | } |
| 746 | |||
| 747 | _doneRunningThisScript = true; | ||
| 748 | } | 763 | } |
| 749 | 764 | ||
| 750 | // NOTE: This is private because it must be called on the same thread that created the timers, which is why | 765 | // NOTE: This is private because it must be called on the same thread that created the timers, which is why |
| @@ -791,13 +806,13 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM · 40 unmodified lines | |||
| 791 | void ScriptEngine::timerFired() { | 806 | void ScriptEngine::timerFired() { |
| 792 | QTimer* callingTimer = reinterpret_cast<QTimer*>(sender()); | 807 | QTimer* callingTimer = reinterpret_cast<QTimer*>(sender()); |
| 793 | QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); | 808 | QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); |
| 794 | 809 | ||
| 795 | if (!callingTimer->isActive()) { | 810 | if (!callingTimer->isActive()) { |
| 796 | // this timer is done, we can kill it | 811 | // this timer is done, we can kill it |
| 797 | _timerFunctionMap.remove(callingTimer); | 812 | _timerFunctionMap.remove(callingTimer); |
| 798 | delete callingTimer; | 813 | delete callingTimer; |
| 799 | } | 814 | } |
| 800 | 815 | ||
| 801 | // call the associated JS function, if it exists | 816 | // call the associated JS function, if it exists |
| 802 | if (timerFunction.isValid()) { | 817 | if (timerFunction.isValid()) { |
| 803 | timerFunction.call(); | 818 | timerFunction.call(); |
| @@ -808,14 +823,14 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 4 unmodified lines | |||
| 808 | // create the timer, add it to the map, and start it | 823 | // create the timer, add it to the map, and start it |
| 809 | QTimer* newTimer = new QTimer(this); | 824 | QTimer* newTimer = new QTimer(this); |
| 810 | newTimer->setSingleShot(isSingleShot); | 825 | newTimer->setSingleShot(isSingleShot); |
| 811 | 826 | ||
| 812 | connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); | 827 | connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); |
| 813 | 828 | ||
| 814 | // make sure the timer stops when the script does | 829 | // make sure the timer stops when the script does |
| 815 | connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); | 830 | connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); |
| 816 | 831 | ||
| 817 | _timerFunctionMap.insert(newTimer, function); | 832 | _timerFunctionMap.insert(newTimer, function); |
| 818 | 833 | ||
| 819 | newTimer->start(intervalMS); | 834 | newTimer->start(intervalMS); |
| 820 | return newTimer; | 835 | return newTimer; |
| 821 | } | 836 | } |
| @@ -825,7 +840,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) · 3 unmodified lines | |||
| 825 | qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename(); | 840 | qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename(); |
| 826 | return NULL; // bail early | 841 | return NULL; // bail early |
| 827 | } | 842 | } |
| 828 | 843 | ||
| 829 | return setupTimerWithInterval(function, intervalMS, false); | 844 | return setupTimerWithInterval(function, intervalMS, false); |
| 830 | } | 845 | } |
| 831 | 846 | ||
| @@ -834,7 +849,7 @@ QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { · 2 unmodified lines | |||
| 834 | qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename(); | 849 | qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename(); |
| 835 | return NULL; // bail early | 850 | return NULL; // bail early |
| 836 | } | 851 | } |
| 837 | 852 | ||
| 838 | return setupTimerWithInterval(function, timeoutMS, true); | 853 | return setupTimerWithInterval(function, timeoutMS, true); |
| 839 | } | 854 | } |
| 840 | 855 | ||
| @@ -852,7 +867,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { · 11 unmodified lines | |||
| 852 | if (!url.scheme().isEmpty()) { | 867 | if (!url.scheme().isEmpty()) { |
| 853 | return url; | 868 | return url; |
| 854 | } | 869 | } |
| 855 | 870 | ||
| 856 | // we apparently weren't a fully qualified url, so, let's assume we're relative | 871 | // we apparently weren't a fully qualified url, so, let's assume we're relative |
| 857 | // to the original URL of our script | 872 | // to the original URL of our script |
| 858 | QUrl parentURL; | 873 | QUrl parentURL; |
| @@ -865,7 +880,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { · 6 unmodified lines | |||
| 865 | if (parentURL.scheme().isEmpty()) { | 880 | if (parentURL.scheme().isEmpty()) { |
| 866 | parentURL = QUrl::fromLocalFile(_fileNameString); | 881 | parentURL = QUrl::fromLocalFile(_fileNameString); |
| 867 | } | 882 | } |
| 868 | 883 | ||
| 869 | // at this point we should have a legitimate fully qualified URL for our parent | 884 | // at this point we should have a legitimate fully qualified URL for our parent |
| 870 | url = parentURL.resolved(url); | 885 | url = parentURL.resolved(url); |
| 871 | return url; | 886 | return url; |
| @@ -898,9 +913,9 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 26 unmodified lines | |||
| 898 | qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL; | 913 | qCDebug(scriptengine) << "Script.include() ignoring previously included url:" << thisURL; |
| 899 | } | 914 | } |
| 900 | } | 915 | } |
| 901 | 916 | ||
| 902 | BatchLoader* loader = new BatchLoader(urls); | 917 | BatchLoader* loader = new BatchLoader(urls); |
| 903 | 918 | ||
| 904 | auto evaluateScripts = [=](const QMap<QUrl, QString>& data) { | 919 | auto evaluateScripts = [=](const QMap<QUrl, QString>& data) { |
| 905 | auto parentURL = _parentURL; | 920 | auto parentURL = _parentURL; |
| 906 | for (QUrl url : urls) { | 921 | for (QUrl url : urls) { |
| @@ -919,17 +934,17 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac · 12 unmodified lines | |||
| 919 | if (callback.isFunction()) { | 934 | if (callback.isFunction()) { |
| 920 | QScriptValue(callback).call(); | 935 | QScriptValue(callback).call(); |
| 921 | } | 936 | } |
| 922 | 937 | ||
| 923 | loader->deleteLater(); | 938 | loader->deleteLater(); |
| 924 | }; | 939 | }; |
| 925 | 940 | ||
| 926 | connect(loader, &BatchLoader::finished, this, evaluateScripts); | 941 | connect(loader, &BatchLoader::finished, this, evaluateScripts); |
| 927 | 942 | ||
| 928 | // If we are destroyed before the loader completes, make sure to clean it up | 943 | // If we are destroyed before the loader completes, make sure to clean it up |
| 929 | connect(this, &QObject::destroyed, loader, &QObject::deleteLater); | 944 | connect(this, &QObject::destroyed, loader, &QObject::deleteLater); |
| 930 | 945 | ||
| 931 | loader->start(); | 946 | loader->start(); |
| 932 | 947 | ||
| 933 | if (!callback.isFunction() && !loader->isFinished()) { | 948 | if (!callback.isFunction() && !loader->isFinished()) { |
| 934 | QEventLoop loop; | 949 | QEventLoop loop; |
| 935 | QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit); | 950 | QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit); |
| @@ -943,7 +958,7 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { · 7 unmodified lines | |||
| 943 | << "includeFile:" << includeFile << "parent script:" << getFilename(); | 958 | << "includeFile:" << includeFile << "parent script:" << getFilename(); |
| 944 | return; // bail early | 959 | return; // bail early |
| 945 | } | 960 | } |
| 946 | 961 | ||
| 947 | QStringList urls; | 962 | QStringList urls; |
| 948 | urls.append(includeFile); | 963 | urls.append(includeFile); |
| 949 | include(urls, callback); | 964 | include(urls, callback); |
| @@ -958,7 +973,7 @@ void ScriptEngine::load(const QString& loadFile) { · 8 unmodified lines | |||
| 958 | << "loadFile:" << loadFile << "parent script:" << getFilename(); | 973 | << "loadFile:" << loadFile << "parent script:" << getFilename(); |
| 959 | return; // bail early | 974 | return; // bail early |
| 960 | } | 975 | } |
| 961 | 976 | ||
| 962 | QUrl url = resolvePath(loadFile); | 977 | QUrl url = resolvePath(loadFile); |
| 963 | if (_isReloading) { | 978 | if (_isReloading) { |
| 964 | auto scriptCache = DependencyManager::get<ScriptCache>(); | 979 | auto scriptCache = DependencyManager::get<ScriptCache>(); |
| @@ -1003,7 +1018,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 38 unmodified lines | |||
| 1003 | qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | 1018 | qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " |
| 1004 | "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload; | 1019 | "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload; |
| 1005 | #endif | 1020 | #endif |
| 1006 | 1021 | ||
| 1007 | QMetaObject::invokeMethod(this, "loadEntityScript", | 1022 | QMetaObject::invokeMethod(this, "loadEntityScript", |
| 1008 | Q_ARG(const EntityItemID&, entityID), | 1023 | Q_ARG(const EntityItemID&, entityID), |
| 1009 | Q_ARG(const QString&, entityScript), | 1024 | Q_ARG(const QString&, entityScript), |
| @@ -1014,10 +1029,10 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 4 unmodified lines | |||
| 1014 | qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] " | 1029 | qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] " |
| 1015 | "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload; | 1030 | "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload; |
| 1016 | #endif | 1031 | #endif |
| 1017 | 1032 | ||
| 1018 | // If we've been called our known entityScripts should not know about us.. | 1033 | // If we've been called our known entityScripts should not know about us.. |
| 1019 | assert(!_entityScripts.contains(entityID)); | 1034 | assert(!_entityScripts.contains(entityID)); |
| 1020 | 1035 | ||
| 1021 | #ifdef THREAD_DEBUGGING | 1036 | #ifdef THREAD_DEBUGGING |
| 1022 | qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; | 1037 | qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; |
| 1023 | #endif | 1038 | #endif |
| @@ -1025,7 +1040,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 1 unmodified line | |||
| 1025 | #ifdef THREAD_DEBUGGING | 1040 | #ifdef THREAD_DEBUGGING |
| 1026 | qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; | 1041 | qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; |
| 1027 | #endif | 1042 | #endif |
| 1028 | 1043 | ||
| 1029 | this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success); | 1044 | this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success); |
| 1030 | }, forceRedownload); | 1045 | }, forceRedownload); |
| 1031 | } | 1046 | } |
| @@ -1038,7 +1053,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 6 unmodified lines | |||
| 1038 | qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | 1053 | qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " |
| 1039 | "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success; | 1054 | "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success; |
| 1040 | #endif | 1055 | #endif |
| 1041 | 1056 | ||
| 1042 | QMetaObject::invokeMethod(this, "entityScriptContentAvailable", | 1057 | QMetaObject::invokeMethod(this, "entityScriptContentAvailable", |
| 1043 | Q_ARG(const EntityItemID&, entityID), | 1058 | Q_ARG(const EntityItemID&, entityID), |
| 1044 | Q_ARG(const QString&, scriptOrURL), | 1059 | Q_ARG(const QString&, scriptOrURL), |
| @@ -1047,15 +1062,15 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 2 unmodified lines | |||
| 1047 | Q_ARG(bool, success)); | 1062 | Q_ARG(bool, success)); |
| 1048 | return; | 1063 | return; |
| 1049 | } | 1064 | } |
| 1050 | 1065 | ||
| 1051 | #ifdef THREAD_DEBUGGING | 1066 | #ifdef THREAD_DEBUGGING |
| 1052 | qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; | 1067 | qDebug() << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; |
| 1053 | #endif | 1068 | #endif |
| 1054 | 1069 | ||
| 1055 | auto scriptCache = DependencyManager::get<ScriptCache>(); | 1070 | auto scriptCache = DependencyManager::get<ScriptCache>(); |
| 1056 | bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); | 1071 | bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); |
| 1057 | auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); | 1072 | auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); |
| 1058 | 1073 | ||
| 1059 | QScriptProgram program(contents, fileName); | 1074 | QScriptProgram program(contents, fileName); |
| 1060 | if (!hasCorrectSyntax(program)) { | 1075 | if (!hasCorrectSyntax(program)) { |
| 1061 | if (!isFileUrl) { | 1076 | if (!isFileUrl) { |
| @@ -1063,17 +1078,17 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 1 unmodified line | |||
| 1063 | } | 1078 | } |
| 1064 | return; // done processing script | 1079 | return; // done processing script |
| 1065 | } | 1080 | } |
| 1066 | 1081 | ||
| 1067 | if (isURL) { | 1082 | if (isURL) { |
| 1068 | setParentURL(scriptOrURL); | 1083 | setParentURL(scriptOrURL); |
| 1069 | } | 1084 | } |
| 1070 | 1085 | ||
| 1071 | QScriptEngine sandbox; | 1086 | QScriptEngine sandbox; |
| 1072 | QScriptValue testConstructor = sandbox.evaluate(program); | 1087 | QScriptValue testConstructor = sandbox.evaluate(program); |
| 1073 | if (hadUncaughtExceptions(sandbox, program.fileName())) { | 1088 | if (hadUncaughtExceptions(sandbox, program.fileName())) { |
| 1074 | return; | 1089 | return; |
| 1075 | } | 1090 | } |
| 1076 | 1091 | ||
| 1077 | if (!testConstructor.isFunction()) { | 1092 | if (!testConstructor.isFunction()) { |
| 1078 | qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" | 1093 | qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" |
| 1079 | " NOT CONSTRUCTOR\n" | 1094 | " NOT CONSTRUCTOR\n" |
| @@ -1083,13 +1098,13 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 3 unmodified lines | |||
| 1083 | } | 1098 | } |
| 1084 | return; // done processing script | 1099 | return; // done processing script |
| 1085 | } | 1100 | } |
| 1086 | 1101 | ||
| 1087 | int64_t lastModified = 0; | 1102 | int64_t lastModified = 0; |
| 1088 | if (isFileUrl) { | 1103 | if (isFileUrl) { |
| 1089 | QString file = QUrl(scriptOrURL).toLocalFile(); | 1104 | QString file = QUrl(scriptOrURL).toLocalFile(); |
| 1090 | lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); | 1105 | lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); |
| 1091 | } | 1106 | } |
| 1092 | 1107 | ||
| 1093 | QScriptValue entityScriptConstructor = evaluate(contents, fileName); | 1108 | QScriptValue entityScriptConstructor = evaluate(contents, fileName); |
| 1094 | QScriptValue entityScriptObject = entityScriptConstructor.construct(); | 1109 | QScriptValue entityScriptObject = entityScriptConstructor.construct(); |
| 1095 | EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; | 1110 | EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; |
| @@ -1097,7 +1112,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 1 unmodified line | |||
| 1097 | if (isURL) { | 1112 | if (isURL) { |
| 1098 | setParentURL(""); | 1113 | setParentURL(""); |
| 1099 | } | 1114 | } |
| 1100 | 1115 | ||
| 1101 | // if we got this far, then call the preload method | 1116 | // if we got this far, then call the preload method |
| 1102 | callEntityScriptMethod(entityID, "preload"); | 1117 | callEntityScriptMethod(entityID, "preload"); |
| 1103 | } | 1118 | } |
| @@ -1108,7 +1123,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 4 unmodified lines | |||
| 1108 | qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | 1123 | qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " |
| 1109 | "entityID:" << entityID; | 1124 | "entityID:" << entityID; |
| 1110 | #endif | 1125 | #endif |
| 1111 | 1126 | ||
| 1112 | QMetaObject::invokeMethod(this, "unloadEntityScript", | 1127 | QMetaObject::invokeMethod(this, "unloadEntityScript", |
| 1113 | Q_ARG(const EntityItemID&, entityID)); | 1128 | Q_ARG(const EntityItemID&, entityID)); |
| 1114 | return; | 1129 | return; |
| @@ -1117,7 +1132,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { · 2 unmodified lines | |||
| 1117 | qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] " | 1132 | qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] " |
| 1118 | "entityID:" << entityID; | 1133 | "entityID:" << entityID; |
| 1119 | #endif | 1134 | #endif |
| 1120 | 1135 | ||
| 1121 | if (_entityScripts.contains(entityID)) { | 1136 | if (_entityScripts.contains(entityID)) { |
| 1122 | callEntityScriptMethod(entityID, "unload"); | 1137 | callEntityScriptMethod(entityID, "unload"); |
| 1123 | _entityScripts.remove(entityID); | 1138 | _entityScripts.remove(entityID); |
| @@ -1129,7 +1144,7 @@ void ScriptEngine::unloadAllEntityScripts() { · 5 unmodified lines | |||
| 1129 | #ifdef THREAD_DEBUGGING | 1144 | #ifdef THREAD_DEBUGGING |
| 1130 | qDebug() << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; | 1145 | qDebug() << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; |
| 1131 | #endif | 1146 | #endif |
| 1132 | 1147 | ||
| 1133 | QMetaObject::invokeMethod(this, "unloadAllEntityScripts"); | 1148 | QMetaObject::invokeMethod(this, "unloadAllEntityScripts"); |
| 1134 | return; | 1149 | return; |
| 1135 | } | 1150 | } |
| @@ -1146,21 +1161,21 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 10 unmodified lines | |||
| 1146 | if (!_entityScripts.contains(entityID)) { | 1161 | if (!_entityScripts.contains(entityID)) { |
| 1147 | return; | 1162 | return; |
| 1148 | } | 1163 | } |
| 1149 | 1164 | ||
| 1150 | static bool recurseGuard = false; | 1165 | static bool recurseGuard = false; |
| 1151 | if (recurseGuard) { | 1166 | if (recurseGuard) { |
| 1152 | return; | 1167 | return; |
| 1153 | } | 1168 | } |
| 1154 | recurseGuard = true; | 1169 | recurseGuard = true; |
| 1155 | 1170 | ||
| 1156 | EntityScriptDetails details = _entityScripts[entityID]; | 1171 | EntityScriptDetails details = _entityScripts[entityID]; |
| 1157 | // Check to see if a file based script needs to be reloaded (easier debugging) | 1172 | // Check to see if a file based script needs to be reloaded (easier debugging) |
| 1158 | if (details.lastModified > 0) { | 1173 | if (details.lastModified > 0) { |
| 1159 | QString filePath = QUrl(details.scriptText).toLocalFile(); | 1174 | QString filePath = QUrl(details.scriptText).toLocalFile(); |
| 1160 | auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch(); | 1175 | auto lastModified = QFileInfo(filePath).lastModified().toMSecsSinceEpoch(); |
| 1161 | if (lastModified > details.lastModified) { | 1176 | if (lastModified > details.lastModified) { |
| 1162 | qDebug() << "Reloading modified script " << details.scriptText; | 1177 | qCDebug(scriptengine) << "Reloading modified script " << details.scriptText; |
| 1163 | 1178 | ||
| 1164 | QFile file(filePath); | 1179 | QFile file(filePath); |
| 1165 | file.open(QIODevice::ReadOnly); | 1180 | file.open(QIODevice::ReadOnly); |
| 1166 | QString scriptContents = QTextStream(&file).readAll(); | 1181 | QString scriptContents = QTextStream(&file).readAll(); |
| @@ -1182,7 +1197,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 15 unmodified lines | |||
| 1182 | 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() << "] " |
| 1183 | "entityID:" << entityID << "methodName:" << methodName; | 1198 | "entityID:" << entityID << "methodName:" << methodName; |
| 1184 | #endif | 1199 | #endif |
| 1185 | 1200 | ||
| 1186 | QMetaObject::invokeMethod(this, "callEntityScriptMethod", | 1201 | QMetaObject::invokeMethod(this, "callEntityScriptMethod", |
| 1187 | Q_ARG(const EntityItemID&, entityID), | 1202 | Q_ARG(const EntityItemID&, entityID), |
| 1188 | Q_ARG(const QString&, methodName), | 1203 | Q_ARG(const QString&, methodName), |
| @@ -1193,7 +1208,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines | |||
| 1193 | qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " | 1208 | qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " |
| 1194 | "entityID:" << entityID << "methodName:" << methodName; | 1209 | "entityID:" << entityID << "methodName:" << methodName; |
| 1195 | #endif | 1210 | #endif |
| 1196 | 1211 | ||
| 1197 | refreshFileScript(entityID); | 1212 | refreshFileScript(entityID); |
| 1198 | if (_entityScripts.contains(entityID)) { | 1213 | if (_entityScripts.contains(entityID)) { |
| 1199 | EntityScriptDetails details = _entityScripts[entityID]; | 1214 | EntityScriptDetails details = _entityScripts[entityID]; |
| @@ -1204,7 +1219,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines | |||
| 1204 | args << qScriptValueFromSequence(this, params); | 1219 | args << qScriptValueFromSequence(this, params); |
| 1205 | entityScript.property(methodName).call(entityScript, args); | 1220 | entityScript.property(methodName).call(entityScript, args); |
| 1206 | } | 1221 | } |
| 1207 | 1222 | ||
| 1208 | } | 1223 | } |
| 1209 | } | 1224 | } |
| 1210 | 1225 | ||
| @@ -1214,7 +1229,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 3 unmodified lines | |||
| 1214 | qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | 1229 | qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " |
| 1215 | "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; | 1230 | "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; |
| 1216 | #endif | 1231 | #endif |
| 1217 | 1232 | ||
| 1218 | QMetaObject::invokeMethod(this, "callEntityScriptMethod", | 1233 | QMetaObject::invokeMethod(this, "callEntityScriptMethod", |
| 1219 | Q_ARG(const EntityItemID&, entityID), | 1234 | Q_ARG(const EntityItemID&, entityID), |
| 1220 | Q_ARG(const QString&, methodName), | 1235 | Q_ARG(const QString&, methodName), |
| @@ -1225,7 +1240,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 4 unmodified lines | |||
| 1225 | qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " | 1240 | qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " |
| 1226 | "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; | 1241 | "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; |
| 1227 | #endif | 1242 | #endif |
| 1228 | 1243 | ||
| 1229 | refreshFileScript(entityID); | 1244 | refreshFileScript(entityID); |
| 1230 | if (_entityScripts.contains(entityID)) { | 1245 | if (_entityScripts.contains(entityID)) { |
| 1231 | EntityScriptDetails details = _entityScripts[entityID]; | 1246 | EntityScriptDetails details = _entityScripts[entityID]; |
| @@ -1246,7 +1261,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 14 unmodified lines | |||
| 1246 | qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " | 1261 | qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " |
| 1247 | "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; | 1262 | "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; |
| 1248 | #endif | 1263 | #endif |
| 1249 | 1264 | ||
| 1250 | QMetaObject::invokeMethod(this, "callEntityScriptMethod", | 1265 | QMetaObject::invokeMethod(this, "callEntityScriptMethod", |
| 1251 | Q_ARG(const EntityItemID&, entityID), | 1266 | Q_ARG(const EntityItemID&, entityID), |
| 1252 | Q_ARG(const QString&, methodName), | 1267 | Q_ARG(const QString&, methodName), |
| @@ -1271,4 +1286,4 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 18 unmodified lines | |||
| 1271 | entityScript.property(methodName).call(entityScript, args); | 1286 | entityScript.property(methodName).call(entityScript, args); |
| 1272 | } | 1287 | } |
| 1273 | } | 1288 | } |
| 1274 | } | 1289 | } |