Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 14 files). Show all
Unified · Split
| @@ -29,7 +29,6 @@ · 28 unmodified lines | ||
| 29 | 29 | #include "LocalVoxels.h" |
| 30 | 30 | #include "ScriptEngine.h" |
| 31 | 31 | |
| 32 | −int ScriptEngine::_scriptNumber = 1; | |
| 33 | 32 | VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; |
| 34 | 33 | ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface; |
| 35 | 34 | |
| @@ -41,7 +40,7 @@ static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* eng · 5 unmodified lines | ||
| 41 | 40 | } |
| 42 | 41 | |
| 43 | 42 | |
| 44 | −ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, const QString& fileNameString, | |
| 43 | +ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, | |
| 45 | 44 | AbstractControllerScriptingInterface* controllerScriptingInterface) : |
| 46 | 45 | |
| 47 | 46 | _scriptContents(scriptContents), |
| @@ -58,26 +57,15 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co · 10 unmodified lines | ||
| 58 | 57 | _numAvatarSoundSentBytes(0), |
| 59 | 58 | _controllerScriptingInterface(controllerScriptingInterface), |
| 60 | 59 | _avatarData(NULL), |
| 61 | − _wantMenuItems(wantMenuItems), | |
| 62 | − _scriptMenuName(), | |
| 60 | + _scriptName(), | |
| 63 | 61 | _fileNameString(fileNameString), |
| 64 | 62 | _quatLibrary(), |
| 65 | 63 | _vec3Library() |
| 66 | 64 | { |
| 67 | − // some clients will use these menu features | |
| 68 | − if (!fileNameString.isEmpty()) { | |
| 69 | − _scriptMenuName = "Stop "; | |
| 70 | − _scriptMenuName.append(qPrintable(fileNameString)); | |
| 71 | − _scriptMenuName.append(QString(" [%1]").arg(_scriptNumber)); | |
| 72 | − } else { | |
| 73 | − _scriptMenuName = "Stop Script "; | |
| 74 | − _scriptMenuName.append(_scriptNumber); | |
| 75 | − } | |
| 76 | − _scriptNumber++; | |
| 77 | 65 | } |
| 78 | 66 | |
| 79 | −ScriptEngine::ScriptEngine(const QUrl& scriptURL, bool wantMenuItems, | |
| 80 | − AbstractControllerScriptingInterface* controllerScriptingInterface) : | |
| 67 | +ScriptEngine::ScriptEngine(const QUrl& scriptURL, | |
| 68 | + AbstractControllerScriptingInterface* controllerScriptingInterface) : | |
| 81 | 69 | _scriptContents(), |
| 82 | 70 | _isFinished(false), |
| 83 | 71 | _isRunning(false), |
| @@ -92,32 +80,21 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, bool wantMenuItems, · 8 unmodified lines | ||
| 92 | 80 | _numAvatarSoundSentBytes(0), |
| 93 | 81 | _controllerScriptingInterface(controllerScriptingInterface), |
| 94 | 82 | _avatarData(NULL), |
| 95 | − _wantMenuItems(wantMenuItems), | |
| 96 | − _scriptMenuName(), | |
| 83 | + _scriptName(), | |
| 97 | 84 | _fileNameString(), |
| 98 | 85 | _quatLibrary(), |
| 99 | 86 | _vec3Library() |
| 100 | 87 | { |
| 101 | 88 | QString scriptURLString = scriptURL.toString(); |
| 102 | 89 | _fileNameString = scriptURLString; |
| 103 | − // some clients will use these menu features | |
| 104 | − if (!scriptURLString.isEmpty()) { | |
| 105 | − _scriptMenuName = "Stop "; | |
| 106 | − _scriptMenuName.append(qPrintable(scriptURLString)); | |
| 107 | − _scriptMenuName.append(QString(" [%1]").arg(_scriptNumber)); | |
| 108 | − } else { | |
| 109 | − _scriptMenuName = "Stop Script "; | |
| 110 | − _scriptMenuName.append(_scriptNumber); | |
| 111 | − } | |
| 112 | − _scriptNumber++; | |
| 113 | − | |
| 90 | + | |
| 114 | 91 | QUrl url(scriptURL); |
| 115 | − | |
| 92 | + | |
| 116 | 93 | // if the scheme is empty, maybe they typed in a file, let's try |
| 117 | 94 | if (url.scheme().isEmpty()) { |
| 118 | 95 | url = QUrl::fromLocalFile(scriptURLString); |
| 119 | 96 | } |
| 120 | − | |
| 97 | + | |
| 121 | 98 | // ok, let's see if it's valid... and if so, load it |
| 122 | 99 | if (url.isValid()) { |
| 123 | 100 | if (url.scheme() == "file") { |
| @@ -144,16 +121,16 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, bool wantMenuItems, · 20 unmodified lines | ||
| 144 | 121 | |
| 145 | 122 | void ScriptEngine::setIsAvatar(bool isAvatar) { |
| 146 | 123 | _isAvatar = isAvatar; |
| 147 | − | |
| 124 | + | |
| 148 | 125 | if (_isAvatar && !_avatarIdentityTimer) { |
| 149 | 126 | // set up the avatar timers |
| 150 | 127 | _avatarIdentityTimer = new QTimer(this); |
| 151 | 128 | _avatarBillboardTimer = new QTimer(this); |
| 152 | − | |
| 129 | + | |
| 153 | 130 | // connect our slot |
| 154 | 131 | connect(_avatarIdentityTimer, &QTimer::timeout, this, &ScriptEngine::sendAvatarIdentityPacket); |
| 155 | 132 | connect(_avatarBillboardTimer, &QTimer::timeout, this, &ScriptEngine::sendAvatarBillboardPacket); |
| 156 | − | |
| 133 | + | |
| 157 | 134 | // start the timers |
| 158 | 135 | _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); |
| 159 | 136 | _avatarBillboardTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS); |
| @@ -162,20 +139,14 @@ void ScriptEngine::setIsAvatar(bool isAvatar) { · 2 unmodified lines | ||
| 162 | 139 | |
| 163 | 140 | void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectName) { |
| 164 | 141 | _avatarData = avatarData; |
| 165 | − | |
| 142 | + | |
| 166 | 143 | // remove the old Avatar property, if it exists |
| 167 | 144 | _engine.globalObject().setProperty(objectName, QScriptValue()); |
| 168 | − | |
| 145 | + | |
| 169 | 146 | // give the script engine the new Avatar script property |
| 170 | 147 | registerGlobalObject(objectName, _avatarData); |
| 171 | 148 | } |
| 172 | 149 | |
| 173 | −void ScriptEngine::cleanupMenuItems() { | |
| 174 | − if (_wantMenuItems) { | |
| 175 | − emit cleanupMenuItem(_scriptMenuName); | |
| 176 | − } | |
| 177 | −} | |
| 178 | − | |
| 179 | 150 | bool ScriptEngine::setScriptContents(const QString& scriptContents, const QString& fileNameString) { |
| 180 | 151 | if (_isRunning) { |
| 181 | 152 | return false; |
| @@ -203,7 +174,7 @@ void ScriptEngine::init() { · 21 unmodified lines | ||
| 203 | 174 | registerVoxelMetaTypes(&_engine); |
| 204 | 175 | registerEventTypes(&_engine); |
| 205 | 176 | registerMenuItemProperties(&_engine); |
| 206 | − | |
| 177 | + | |
| 207 | 178 | qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); |
| 208 | 179 | qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); |
| 209 | 180 | qScriptRegisterSequenceMetaType<QVector<ParticleID> >(&_engine); |
| @@ -216,7 +187,7 @@ void ScriptEngine::init() { · 6 unmodified lines | ||
| 216 | 187 | |
| 217 | 188 | QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject<AudioInjectorOptions>(); |
| 218 | 189 | _engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); |
| 219 | − | |
| 190 | + | |
| 220 | 191 | QScriptValue localVoxelsValue = _engine.scriptValueFromQMetaObject<LocalVoxels>(); |
| 221 | 192 | _engine.globalObject().setProperty("LocalVoxels", localVoxelsValue); |
| 222 | 193 | |
| @@ -285,9 +256,9 @@ void ScriptEngine::run() { · 62 unmodified lines | ||
| 285 | 256 | gettimeofday(&startTime, NULL); |
| 286 | 257 | |
| 287 | 258 | int thisFrame = 0; |
| 288 | − | |
| 259 | + | |
| 289 | 260 | NodeList* nodeList = NodeList::getInstance(); |
| 290 | − | |
| 261 | + | |
| 291 | 262 | qint64 lastUpdate = usecTimestampNow(); |
| 292 | 263 | |
| 293 | 264 | while (!_isFinished) { |
| @@ -325,36 +296,36 @@ void ScriptEngine::run() { · 31 unmodified lines | ||
| 325 | 296 | _particlesScriptingInterface.getParticlePacketSender()->process(); |
| 326 | 297 | } |
| 327 | 298 | } |
| 328 | − | |
| 299 | + | |
| 329 | 300 | if (_isAvatar && _avatarData) { |
| 330 | − | |
| 301 | + | |
| 331 | 302 | const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000)) + 0.5); |
| 332 | 303 | const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); |
| 333 | − | |
| 304 | + | |
| 334 | 305 | QByteArray avatarPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarData); |
| 335 | 306 | avatarPacket.append(_avatarData->toByteArray()); |
| 336 | − | |
| 307 | + | |
| 337 | 308 | nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer); |
| 338 | − | |
| 309 | + | |
| 339 | 310 | if (_isListeningToAudioStream || _avatarSound) { |
| 340 | 311 | // if we have an avatar audio stream then send it out to our audio-mixer |
| 341 | 312 | bool silentFrame = true; |
| 342 | − | |
| 313 | + | |
| 343 | 314 | int16_t numAvailableSamples = SCRIPT_AUDIO_BUFFER_SAMPLES; |
| 344 | 315 | const int16_t* nextSoundOutput = NULL; |
| 345 | − | |
| 316 | + | |
| 346 | 317 | if (_avatarSound) { |
| 347 | − | |
| 318 | + | |
| 348 | 319 | const QByteArray& soundByteArray = _avatarSound->getByteArray(); |
| 349 | 320 | nextSoundOutput = reinterpret_cast<const int16_t*>(soundByteArray.data() |
| 350 | 321 | + _numAvatarSoundSentBytes); |
| 351 | − | |
| 322 | + | |
| 352 | 323 | int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > SCRIPT_AUDIO_BUFFER_BYTES |
| 353 | 324 | ? SCRIPT_AUDIO_BUFFER_BYTES |
| 354 | 325 | : soundByteArray.size() - _numAvatarSoundSentBytes; |
| 355 | 326 | numAvailableSamples = numAvailableBytes / sizeof(int16_t); |
| 356 | − | |
| 357 | − | |
| 327 | + | |
| 328 | + | |
| 358 | 329 | // check if the all of the _numAvatarAudioBufferSamples to be sent are silence |
| 359 | 330 | for (int i = 0; i < numAvailableSamples; ++i) { |
| 360 | 331 | if (nextSoundOutput[i] != 0) { |
| @@ -362,7 +333,7 @@ void ScriptEngine::run() { · 1 unmodified line | ||
| 362 | 333 | break; |
| 363 | 334 | } |
| 364 | 335 | } |
| 365 | − | |
| 336 | + | |
| 366 | 337 | _numAvatarSoundSentBytes += numAvailableBytes; |
| 367 | 338 | if (_numAvatarSoundSentBytes == soundByteArray.size()) { |
| 368 | 339 | // we're done with this sound object - so set our pointer back to NULL |
| @@ -371,24 +342,24 @@ void ScriptEngine::run() { · 2 unmodified lines | ||
| 371 | 342 | _numAvatarSoundSentBytes = 0; |
| 372 | 343 | } |
| 373 | 344 | } |
| 374 | − | |
| 345 | + | |
| 375 | 346 | QByteArray audioPacket = byteArrayWithPopulatedHeader(silentFrame |
| 376 | 347 | ? PacketTypeSilentAudioFrame |
| 377 | 348 | : PacketTypeMicrophoneAudioNoEcho); |
| 378 | − | |
| 349 | + | |
| 379 | 350 | QDataStream packetStream(&audioPacket, QIODevice::Append); |
| 380 | − | |
| 351 | + | |
| 381 | 352 | // use the orientation and position of this avatar for the source of this audio |
| 382 | 353 | packetStream.writeRawData(reinterpret_cast<const char*>(&_avatarData->getPosition()), sizeof(glm::vec3)); |
| 383 | 354 | glm::quat headOrientation = _avatarData->getHeadOrientation(); |
| 384 | 355 | packetStream.writeRawData(reinterpret_cast<const char*>(&headOrientation), sizeof(glm::quat)); |
| 385 | − | |
| 356 | + | |
| 386 | 357 | if (silentFrame) { |
| 387 | 358 | if (!_isListeningToAudioStream) { |
| 388 | 359 | // if we have a silent frame and we're not listening then just send nothing and break out of here |
| 389 | 360 | break; |
| 390 | 361 | } |
| 391 | − | |
| 362 | + | |
| 392 | 363 | // write the number of silent samples so the audio-mixer can uphold timing |
| 393 | 364 | packetStream.writeRawData(reinterpret_cast<const char*>(&SCRIPT_AUDIO_BUFFER_SAMPLES), sizeof(int16_t)); |
| 394 | 365 | } else if (nextSoundOutput) { |
| @@ -396,7 +367,7 @@ void ScriptEngine::run() { · 1 unmodified line | ||
| 396 | 367 | packetStream.writeRawData(reinterpret_cast<const char*>(nextSoundOutput), |
| 397 | 368 | numAvailableSamples * sizeof(int16_t)); |
| 398 | 369 | } |
| 399 | − | |
| 370 | + | |
| 400 | 371 | nodeList->broadcastToNodes(audioPacket, NodeSet() << NodeType::AudioMixer); |
| 401 | 372 | } |
| 402 | 373 | } |
| @@ -412,10 +383,10 @@ void ScriptEngine::run() { · 9 unmodified lines | ||
| 412 | 383 | } |
| 413 | 384 | } |
| 414 | 385 | emit scriptEnding(); |
| 415 | − | |
| 386 | + | |
| 416 | 387 | // kill the avatar identity timer |
| 417 | 388 | delete _avatarIdentityTimer; |
| 418 | − | |
| 389 | + | |
| 419 | 390 | if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) { |
| 420 | 391 | // release the queue of edit voxel messages. |
| 421 | 392 | _voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); |
| @@ -435,8 +406,6 @@ void ScriptEngine::run() { · 13 unmodified lines | ||
| 435 | 406 | _particlesScriptingInterface.getParticlePacketSender()->process(); |
| 436 | 407 | } |
| 437 | 408 | } |
| 438 | − | |
| 439 | − cleanupMenuItems(); | |
| 440 | 409 | |
| 441 | 410 | // If we were on a thread, then wait till it's done |
| 442 | 411 | if (thread()) { |
| @@ -444,7 +413,7 @@ void ScriptEngine::run() { · 1 unmodified line | ||
| 444 | 413 | } |
| 445 | 414 | |
| 446 | 415 | emit finished(_fileNameString); |
| 447 | − | |
| 416 | + | |
| 448 | 417 | _isRunning = false; |
| 449 | 418 | } |
| 450 | 419 | |
| @@ -454,13 +423,13 @@ void ScriptEngine::stop() { · 3 unmodified lines | ||
| 454 | 423 | |
| 455 | 424 | void ScriptEngine::timerFired() { |
| 456 | 425 | QTimer* callingTimer = reinterpret_cast<QTimer*>(sender()); |
| 457 | − | |
| 426 | + | |
| 458 | 427 | // call the associated JS function, if it exists |
| 459 | 428 | QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); |
| 460 | 429 | if (timerFunction.isValid()) { |
| 461 | 430 | timerFunction.call(); |
| 462 | 431 | } |
| 463 | − | |
| 432 | + | |
| 464 | 433 | if (!callingTimer->isActive()) { |
| 465 | 434 | // this timer is done, we can kill it |
| 466 | 435 | delete callingTimer; |
| @@ -471,14 +440,14 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int · 4 unmodified lines | ||
| 471 | 440 | // create the timer, add it to the map, and start it |
| 472 | 441 | QTimer* newTimer = new QTimer(this); |
| 473 | 442 | newTimer->setSingleShot(isSingleShot); |
| 474 | − | |
| 443 | + | |
| 475 | 444 | connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); |
| 476 | − | |
| 445 | + | |
| 477 | 446 | // make sure the timer stops when the script does |
| 478 | 447 | connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); |
| 479 | − | |
| 448 | + | |
| 480 | 449 | _timerFunctionMap.insert(newTimer, function); |
| 481 | − | |
| 450 | + | |
| 482 | 451 | newTimer->start(intervalMS); |
| 483 | 452 | return newTimer; |
| 484 | 453 | } |
| @@ -505,17 +474,17 @@ QUrl ScriptEngine::resolveInclude(const QString& include) const { · 20 unmodified lines | ||
| 505 | 474 | if (!url.scheme().isEmpty()) { |
| 506 | 475 | return url; |
| 507 | 476 | } |
| 508 | − | |
| 509 | − // we apparently weren't a fully qualified url, so, let's assume we're relative | |
| 477 | + | |
| 478 | + // we apparently weren't a fully qualified url, so, let's assume we're relative | |
| 510 | 479 | // to the original URL of our script |
| 511 | 480 | QUrl parentURL(_fileNameString); |
| 512 | − | |
| 481 | + | |
| 513 | 482 | // if the parent URL's scheme is empty, then this is probably a local file... |
| 514 | 483 | if (parentURL.scheme().isEmpty()) { |
| 515 | 484 | parentURL = QUrl::fromLocalFile(_fileNameString); |
| 516 | 485 | } |
| 517 | − | |
| 518 | − // at this point we should have a legitimate fully qualified URL for our parent | |
| 486 | + | |
| 487 | + // at this point we should have a legitimate fully qualified URL for our parent | |
| 519 | 488 | url = parentURL.resolved(url); |
| 520 | 489 | return url; |
| 521 | 490 | } |
| @@ -543,7 +512,7 @@ void ScriptEngine::include(const QString& includeFile) { · 21 unmodified lines | ||
| 543 | 512 | loop.exec(); |
| 544 | 513 | includeContents = reply->readAll(); |
| 545 | 514 | } |
| 546 | − | |
| 515 | + | |
| 547 | 516 | QScriptValue result = _engine.evaluate(includeContents); |
| 548 | 517 | if (_engine.hasUncaughtException()) { |
| 549 | 518 | int line = _engine.uncaughtExceptionLineNumber(); |