History

Added the new Running Scripts widget

Mohammed Nafees committed 12 years ago

Commit d85d4fe1 parent 89cb1ad14 files · +920 −339Browse files

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

Unified · Split

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