Showing the changes to libraries/script-engine/src/ScriptManager.cpp (1 of 53 files). Show all
Unified · Split
| @@ -24,55 +24,36 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <QtCore/QFuture> |
| 25 | 25 | #include <QtConcurrent/QtConcurrentRun> |
| 26 | 26 | |
| 27 | −#include <QtWidgets/QMainWindow> | |
| 28 | −#include <QtWidgets/QApplication> | |
| 29 | −#include <QtWidgets/QMenuBar> | |
| 30 | −#include <QtWidgets/QMenu> | |
| 31 | − | |
| 32 | −#include <QtNetwork/QNetworkRequest> | |
| 33 | −#include <QtNetwork/QNetworkReply> | |
| 34 | − | |
| 35 | 27 | #include <shared/LocalFileAccessGate.h> |
| 36 | −#include <shared/QtHelpers.h> | |
| 37 | 28 | #include <shared/AbstractLoggerInterface.h> |
| 38 | −#include <AudioConstants.h> | |
| 39 | −#include <AudioEffectOptions.h> | |
| 40 | −#include <AvatarData.h> | |
| 41 | 29 | #include <DebugDraw.h> |
| 42 | −#include <EntityScriptingInterface.h> | |
| 43 | 30 | #include <MessagesClient.h> |
| 44 | −#include <NetworkAccessManager.h> | |
| 31 | +#include <OctreeConstants.h> | |
| 45 | 32 | #include <PathUtils.h> |
| 33 | +#include <PortableHighResolutionClock.h> | |
| 34 | +#include <ResourceCache.h> | |
| 35 | +#include <ResourceManager.h> | |
| 46 | 36 | #include <ResourceScriptingInterface.h> |
| 47 | 37 | #include <UserActivityLoggerScriptingInterface.h> |
| 48 | 38 | #include <NodeList.h> |
| 49 | −#include <ScriptAvatarData.h> | |
| 50 | −#include <udt/PacketHeaders.h> | |
| 51 | −#include <UUID.h> | |
| 52 | − | |
| 53 | −#include <controllers/ScriptingInterface.h> | |
| 54 | −#include <AnimationObject.h> | |
| 55 | 39 | |
| 56 | −#include "AudioScriptingInterface.h" | |
| 57 | 40 | #include "AssetScriptingInterface.h" |
| 58 | 41 | #include "BatchLoader.h" |
| 59 | 42 | #include "EventTypes.h" |
| 60 | 43 | #include "FileScriptingInterface.h" // unzip project |
| 61 | 44 | #include "MenuItemProperties.h" |
| 62 | −#include "ScriptAudioInjector.h" | |
| 63 | −#include "ScriptAvatarData.h" | |
| 64 | 45 | #include "ScriptCache.h" |
| 65 | 46 | #include "ScriptContext.h" |
| 66 | −#include "ScriptEngineCast.h" | |
| 67 | −#include "ScriptEngineLogging.h" | |
| 68 | 47 | #include "XMLHttpRequestClass.h" |
| 69 | 48 | #include "WebSocketClass.h" |
| 70 | −#include "RecordingScriptingInterface.h" | |
| 49 | +#include "ScriptEngine.h" | |
| 50 | +#include "ScriptEngineCast.h" | |
| 51 | +#include "ScriptEngineLogging.h" | |
| 71 | 52 | #include "ScriptEngines.h" |
| 72 | 53 | #include "StackTestScriptingInterface.h" |
| 73 | −#include "ModelScriptingInterface.h" | |
| 74 | 54 | #include "ScriptValue.h" |
| 75 | 55 | #include "ScriptValueIterator.h" |
| 56 | +#include "ScriptValueUtils.h" | |
| 76 | 57 | |
| 77 | 58 | #include <Profile.h> |
| 78 | 59 | |
| @@ -94,8 +75,6 @@ const QString ScriptManager::SCRIPT_BACKTRACE_SEP{ "\n " }; · 15 unmodified lines | ||
| 94 | 75 | static const int MAX_MODULE_ID_LENGTH { 4096 }; |
| 95 | 76 | static const int MAX_DEBUG_VALUE_LENGTH { 80 }; |
| 96 | 77 | |
| 97 | −static const ScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = | |
| 98 | − ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects; | |
| 99 | 78 | static const ScriptValue::PropertyFlags READONLY_PROP_FLAGS{ ScriptValue::ReadOnly | ScriptValue::Undeletable }; |
| 100 | 79 | static const ScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS{ READONLY_PROP_FLAGS | ScriptValue::SkipInEnumeration }; |
| 101 | 80 | |
| @@ -108,6 +87,26 @@ int scriptManagerPointerMetaID = qRegisterMetaType<ScriptManagerPointer>(); · 6 unmodified lines | ||
| 108 | 87 | |
| 109 | 88 | Q_DECLARE_METATYPE(ExternalResource::Bucket); |
| 110 | 89 | |
| 90 | +// --- Static script initialization registry | |
| 91 | + | |
| 92 | +static ScriptManager::StaticInitializerNode* rootInitializer = nullptr; | |
| 93 | + | |
| 94 | +void ScriptManager::registerNewStaticInitializer(StaticInitializerNode* dest) { | |
| 95 | + // this function is assumed to be called on LoadLibrary, where we are explicitly operating in single-threaded mode | |
| 96 | + // Therefore there is no mutex or threadsafety here and the structure is assumed not to change after loading | |
| 97 | + dest->prev = rootInitializer; | |
| 98 | + rootInitializer = dest; | |
| 99 | +} | |
| 100 | +static void runStaticInitializers(ScriptManager* manager) { | |
| 101 | + ScriptManager::StaticInitializerNode* here = rootInitializer; | |
| 102 | + while (here != nullptr) { | |
| 103 | + (*here->init)(manager); | |
| 104 | + here = here->prev; | |
| 105 | + } | |
| 106 | +} | |
| 107 | + | |
| 108 | +// --- | |
| 109 | + | |
| 111 | 110 | static ScriptValuePointer debugPrint(ScriptContext* context, ScriptEngine* engine) { |
| 112 | 111 | // assemble the message by concatenating our arguments |
| 113 | 112 | QString message = ""; |
| @@ -172,17 +171,6 @@ static ScriptValuePointer debugPrint(ScriptContext* context, ScriptEngine* engin · 58 unmodified lines | ||
| 172 | 171 | return ScriptValuePointer(); |
| 173 | 172 | } |
| 174 | 173 | |
| 175 | −Q_DECLARE_METATYPE(controller::InputController*) | |
| 176 | −//static int inputControllerPointerId = qRegisterMetaType<controller::InputController*>(); | |
| 177 | − | |
| 178 | −ScriptValuePointer inputControllerToScriptValue(ScriptEngine* engine, controller::InputController* const& in) { | |
| 179 | − return engine->newQObject(in, ScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); | |
| 180 | −} | |
| 181 | − | |
| 182 | −void inputControllerFromScriptValue(const ScriptValuePointer& object, controller::InputController*& out) { | |
| 183 | − out = qobject_cast<controller::InputController*>(object->toQObject()); | |
| 184 | −} | |
| 185 | − | |
| 186 | 174 | // FIXME Come up with a way to properly encode entity IDs in filename |
| 187 | 175 | // The purpose of the following two function is to embed entity ids into entity script filenames |
| 188 | 176 | // so that they show up in stacktraces |
| @@ -522,28 +510,6 @@ void ScriptManager::clearDebugLogWindow() { · 333 unmodified lines | ||
| 522 | 510 | emit clearDebugWindow(); |
| 523 | 511 | } |
| 524 | 512 | |
| 525 | −// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of | |
| 526 | −// callAnimationStateHandler requires that the type be registered. | |
| 527 | −// These two are meaningful, if we ever do want to use them... | |
| 528 | −static ScriptValuePointer animVarMapToScriptValue(ScriptEngine* engine, const AnimVariantMap& parameters) { | |
| 529 | − QStringList unused; | |
| 530 | − return parameters.animVariantMapToScriptValue(engine, unused, false); | |
| 531 | −} | |
| 532 | −static void animVarMapFromScriptValue(const ScriptValuePointer& value, AnimVariantMap& parameters) { | |
| 533 | − parameters.animVariantMapFromScriptValue(value); | |
| 534 | −} | |
| 535 | −// ... while these two are not. But none of the four are ever used. | |
| 536 | −static ScriptValuePointer resultHandlerToScriptValue(ScriptEngine* engine, | |
| 537 | − const AnimVariantResultHandler& resultHandler) { | |
| 538 | − qCCritical(scriptengine) << "Attempt to marshall result handler to javascript"; | |
| 539 | − assert(false); | |
| 540 | − return ScriptValuePointer(); | |
| 541 | −} | |
| 542 | −static void resultHandlerFromScriptValue(const ScriptValuePointer& value, AnimVariantResultHandler& resultHandler) { | |
| 543 | − qCCritical(scriptengine) << "Attempt to marshall result handler from javascript"; | |
| 544 | − assert(false); | |
| 545 | −} | |
| 546 | − | |
| 547 | 513 | // Templated qScriptRegisterMetaType fails to compile with raw pointers |
| 548 | 514 | using ScriptableResourceRawPtr = ScriptableResource*; |
| 549 | 515 | |
| @@ -562,13 +528,10 @@ static ScriptValuePointer scriptableResourceToScriptValue(ScriptEngine* engine, · 12 unmodified lines | ||
| 562 | 528 | auto manager = engine->manager(); |
| 563 | 529 | if (data && manager && !resource->isInScript()) { |
| 564 | 530 | resource->setInScript(true); |
| 565 | − QObject::connect(data.data(), SIGNAL(updateSize(qint64)), manager, SLOT(updateMemoryCost(qint64))); | |
| 531 | + QObject::connect(data.data(), &Resource::updateSize, manager, &ScriptManager::updateMemoryCost); | |
| 566 | 532 | } |
| 567 | 533 | |
| 568 | − auto object = engine->newQObject( | |
| 569 | − const_cast<ScriptableResourceRawPtr>(resource), | |
| 570 | − ScriptEngine::ScriptOwnership, | |
| 571 | − DEFAULT_QOBJECT_WRAP_OPTIONS); | |
| 534 | + auto object = engine->newQObject(const_cast<ScriptableResourceRawPtr>(resource), ScriptEngine::ScriptOwnership); | |
| 572 | 535 | return object; |
| 573 | 536 | } |
| 574 | 537 | |
| @@ -602,22 +565,12 @@ static ScriptValuePointer createScriptableResourcePrototype(ScriptManagerPointer · 27 unmodified lines | ||
| 602 | 565 | } |
| 603 | 566 | |
| 604 | 567 | auto prototypeState = engine->newQObject(state, ScriptEngine::QtOwnership, |
| 605 | − ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeSlots | ScriptEngine::ExcludeSuperClassMethods); | |
| 568 | + ScriptEngine::ExcludeSlots | ScriptEngine::ExcludeSuperClassMethods); | |
| 606 | 569 | prototype->setProperty("State", prototypeState); |
| 607 | 570 | |
| 608 | 571 | return prototype; |
| 609 | 572 | } |
| 610 | 573 | |
| 611 | −ScriptValuePointer avatarDataToScriptValue(ScriptEngine* engine, ScriptAvatarData* const& in) { | |
| 612 | − return engine->newQObject(in, ScriptEngine::ScriptOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); | |
| 613 | −} | |
| 614 | − | |
| 615 | −void avatarDataFromScriptValue(const ScriptValuePointer& object, ScriptAvatarData*& out) { | |
| 616 | − // This is not implemented because there are no slots/properties that take an AvatarSharedPointer from a script | |
| 617 | − assert(false); | |
| 618 | − out = nullptr; | |
| 619 | −} | |
| 620 | − | |
| 621 | 574 | ScriptValuePointer externalResourceBucketToScriptValue(ScriptEngine* engine, ExternalResource::Bucket const& in) { |
| 622 | 575 | return engine->newValue((int)in); |
| 623 | 576 | } |
| @@ -666,27 +619,15 @@ void ScriptManager::init() { · 42 unmodified lines | ||
| 666 | 619 | } |
| 667 | 620 | |
| 668 | 621 | _isInitialized = true; |
| 669 | − auto scriptEngine = _engine.data(); | |
| 622 | + runStaticInitializers(this); | |
| 670 | 623 | |
| 671 | − auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | |
| 672 | − entityScriptingInterface->init(); | |
| 624 | + auto scriptEngine = _engine.data(); | |
| 673 | 625 | |
| 674 | 626 | // register various meta-types |
| 675 | − registerMetaTypes(scriptEngine); | |
| 676 | 627 | registerMIDIMetaTypes(scriptEngine); |
| 677 | 628 | registerEventTypes(scriptEngine); |
| 678 | 629 | registerMenuItemProperties(scriptEngine); |
| 679 | − registerAnimationTypes(scriptEngine); | |
| 680 | − registerAvatarTypes(scriptEngine); | |
| 681 | − registerAudioMetaTypes(scriptEngine); | |
| 682 | − | |
| 683 | − scriptRegisterMetaType(scriptEngine, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue); | |
| 684 | − scriptRegisterMetaType(scriptEngine, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); | |
| 685 | − scriptRegisterMetaType(scriptEngine, EntityPropertyInfoToScriptValue, EntityPropertyInfoFromScriptValue); | |
| 686 | − scriptRegisterMetaType(scriptEngine, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); | |
| 687 | − scriptRegisterMetaType(scriptEngine, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); | |
| 688 | − scriptRegisterMetaType(scriptEngine, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue); | |
| 689 | − scriptRegisterMetaType(scriptEngine, AvatarEntityMapToScriptValue, AvatarEntityMapFromScriptValue); | |
| 630 | + | |
| 690 | 631 | scriptRegisterSequenceMetaType<QVector<QUuid>>(scriptEngine); |
| 691 | 632 | scriptRegisterSequenceMetaType<QVector<EntityItemID>>(scriptEngine); |
| 692 | 633 | |
| @@ -709,12 +650,6 @@ void ScriptManager::init() { · 16 unmodified lines | ||
| 709 | 650 | */ |
| 710 | 651 | scriptEngine->globalObject()->setProperty("print", scriptEngine->newFunction(debugPrint)); |
| 711 | 652 | |
| 712 | − ScriptValuePointer audioEffectOptionsConstructorValue = scriptEngine->newFunction(AudioEffectOptions::constructor); | |
| 713 | − scriptEngine->globalObject()->setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); | |
| 714 | − | |
| 715 | − scriptRegisterMetaType(scriptEngine, injectorToScriptValue, injectorFromScriptValue); | |
| 716 | − scriptRegisterMetaType(scriptEngine, inputControllerToScriptValue, inputControllerFromScriptValue); | |
| 717 | − scriptRegisterMetaType(scriptEngine, avatarDataToScriptValue, avatarDataFromScriptValue); | |
| 718 | 653 | scriptRegisterMetaType(scriptEngine, animationDetailsToScriptValue, animationDetailsFromScriptValue); |
| 719 | 654 | scriptRegisterMetaType(scriptEngine, webSocketToScriptValue, webSocketFromScriptValue); |
| 720 | 655 | scriptRegisterMetaType(scriptEngine, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue); |
| @@ -737,13 +672,8 @@ void ScriptManager::init() { · 16 unmodified lines | ||
| 737 | 672 | scriptRegisterMetaType(scriptEngine, externalResourceBucketToScriptValue, externalResourceBucketFromScriptValue); |
| 738 | 673 | scriptEngine->registerEnum("Script.ExternalPaths", QMetaEnum::fromType<ExternalResource::Bucket>()); |
| 739 | 674 | |
| 740 | − scriptEngine->registerGlobalObject("Audio", DependencyManager::get<AudioScriptingInterface>().data()); | |
| 741 | − | |
| 742 | 675 | scriptEngine->registerGlobalObject("Midi", DependencyManager::get<Midi>().data()); |
| 743 | 676 | |
| 744 | − scriptEngine->registerGlobalObject("Entities", entityScriptingInterface.data()); | |
| 745 | − scriptEngine->registerFunction("Entities", "getMultipleEntityProperties", | |
| 746 | − EntityScriptingInterface::getMultipleEntityProperties); | |
| 747 | 677 | scriptEngine->registerGlobalObject("Quat", &_quatLibrary); |
| 748 | 678 | scriptEngine->registerGlobalObject("Vec3", &_vec3Library); |
| 749 | 679 | scriptEngine->registerGlobalObject("Mat4", &_mat4Library); |
| @@ -762,9 +692,6 @@ void ScriptManager::init() { · 12 unmodified lines | ||
| 762 | 692 | scriptEngine->registerFunction("console", "groupCollapsed", ConsoleScriptingInterface::groupCollapsed, 1); |
| 763 | 693 | scriptEngine->registerFunction("console", "groupEnd", ConsoleScriptingInterface::groupEnd, 0); |
| 764 | 694 | |
| 765 | − scriptRegisterMetaType(scriptEngine, animVarMapToScriptValue, animVarMapFromScriptValue); | |
| 766 | − scriptRegisterMetaType(scriptEngine, resultHandlerToScriptValue, resultHandlerFromScriptValue); | |
| 767 | − | |
| 768 | 695 | // Scriptable cache access |
| 769 | 696 | auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast<ScriptManager>(sharedFromThis())); |
| 770 | 697 | scriptEngine->globalObject()->setProperty("Resource", resourcePrototype); |
| @@ -779,7 +706,6 @@ void ScriptManager::init() { · 8 unmodified lines | ||
| 779 | 706 | |
| 780 | 707 | scriptEngine->registerGlobalObject("DebugDraw", &DebugDraw::getInstance()); |
| 781 | 708 | |
| 782 | − scriptEngine->registerGlobalObject("Model", new ModelScriptingInterface(this)); | |
| 783 | 709 | scriptRegisterMetaType(scriptEngine, meshToScriptValue, meshFromScriptValue); |
| 784 | 710 | scriptRegisterMetaType(scriptEngine, meshesToScriptValue, meshesFromScriptValue); |
| 785 | 711 | |
| @@ -825,6 +751,22 @@ void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QStri · 39 unmodified lines | ||
| 825 | 751 | } |
| 826 | 752 | } |
| 827 | 753 | } |
| 754 | + | |
| 755 | +// Unregister all event handlers for the specified entityID (i.e. the entity is being removed) | |
| 756 | +void ScriptManager::removeAllEventHandlers(const EntityItemID& entityID) { | |
| 757 | + if (QThread::currentThread() != thread()) { | |
| 758 | +#ifdef THREAD_DEBUGGING | |
| 759 | + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::removeAllEventHandlers() called on wrong thread [" << QThread::currentThread() << ", correct thread is " << thread() << " ], ignoring " | |
| 760 | + "entityID:" << entityID; | |
| 761 | +#endif | |
| 762 | + return; | |
| 763 | + } | |
| 764 | + | |
| 765 | + if (_registeredHandlers.contains(entityID)) { | |
| 766 | + _registeredHandlers.remove(entityID); | |
| 767 | + } | |
| 768 | +} | |
| 769 | + | |
| 828 | 770 | // Register the handler. |
| 829 | 771 | void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler) { |
| 830 | 772 | if (QThread::currentThread() != thread()) { |
| @@ -843,117 +785,9 @@ void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& · 12 unmodified lines | ||
| 843 | 785 | qCDebug(scriptengine) << "ScriptManager::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; |
| 844 | 786 | #endif |
| 845 | 787 | |
| 846 | − if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script... | |
| 847 | − // Connect up ALL the handlers to the global entities object's signals. | |
| 848 | − // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) | |
| 849 | − auto entities = DependencyManager::get<EntityScriptingInterface>(); | |
| 850 | − // Bug? These handlers are deleted when entityID is deleted, which is nice. | |
| 851 | − // But if they are created by an entity script on a different entity, should they also be deleted when the entity script unloads? | |
| 852 | − // E.g., suppose a bow has an entity script that causes arrows to be created with a potential lifetime greater than the bow, | |
| 853 | − // and that the entity script adds (e.g., collision) handlers to the arrows. Should those handlers fire if the bow is unloaded? | |
| 854 | − // Also, what about when the entity script is REloaded? | |
| 855 | − // For now, we are leaving them around. Changing that would require some non-trivial digging around to find the | |
| 856 | − // handlers that were added while a given currentEntityIdentifier was in place. I don't think this is dangerous. Just perhaps unexpected. -HRS | |
| 857 | − connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { | |
| 858 | − _registeredHandlers.remove(entityID); | |
| 859 | − }); | |
| 860 | − | |
| 861 | − // Two common cases of event handler, differing only in argument signature. | |
| 862 | − | |
| 863 | − /*@jsdoc | |
| 864 | − * Called when an entity event occurs on an entity as registered with {@link Script.addEventHandler}. | |
| 865 | − * @callback Script~entityEventCallback | |
| 866 | − * @param {Uuid} entityID - The ID of the entity the event has occured on. | |
| 867 | − */ | |
| 868 | − using SingleEntityHandler = std::function<void(const EntityItemID&)>; | |
| 869 | − auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler { | |
| 870 | − return [this, eventName](const EntityItemID& entityItemID) { | |
| 871 | − forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(_engine.data()) }); | |
| 872 | − }; | |
| 873 | − }; | |
| 874 | − | |
| 875 | − /*@jsdoc | |
| 876 | − * Called when a pointer event occurs on an entity as registered with {@link Script.addEventHandler}. | |
| 877 | − * @callback Script~pointerEventCallback | |
| 878 | − * @param {Uuid} entityID - The ID of the entity the event has occurred on. | |
| 879 | − * @param {PointerEvent} pointerEvent - Details of the event. | |
| 880 | − */ | |
| 881 | − using PointerHandler = std::function<void(const EntityItemID&, const PointerEvent&)>; | |
| 882 | − auto makePointerHandler = [this](QString eventName) -> PointerHandler { | |
| 883 | − return [this, eventName](const EntityItemID& entityItemID, const PointerEvent& event) { | |
| 884 | − if (!EntityTree::areEntityClicksCaptured()) { | |
| 885 | − forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(_engine.data()), event.toScriptValue(_engine.data()) }); | |
| 886 | − } | |
| 887 | − }; | |
| 888 | − }; | |
| 889 | − | |
| 890 | − /*@jsdoc | |
| 891 | − * Called when a collision event occurs on an entity as registered with {@link Script.addEventHandler}. | |
| 892 | − * @callback Script~collisionEventCallback | |
| 893 | − * @param {Uuid} entityA - The ID of one entity in the collision. | |
| 894 | − * @param {Uuid} entityB - The ID of the other entity in the collision. | |
| 895 | − * @param {Collision} collisionEvent - Details of the collision. | |
| 896 | − */ | |
| 897 | − using CollisionHandler = std::function<void(const EntityItemID&, const EntityItemID&, const Collision&)>; | |
| 898 | − auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { | |
| 899 | − return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { | |
| 900 | − forwardHandlerCall(idA, eventName, { idA.toScriptValue(_engine.data()), idB.toScriptValue(_engine.data()), | |
| 901 | − collisionToScriptValue(_engine.data(), collision) }); | |
| 902 | − }; | |
| 903 | − }; | |
| 904 | − | |
| 905 | − /*@jsdoc | |
| 906 | − * <p>The name of an entity event. When the entity event occurs, any function that has been registered for that event | |
| 907 | − * via {@link Script.addEventHandler} is called with parameters per the entity event.</p> | |
| 908 | − * <table> | |
| 909 | − * <thead> | |
| 910 | − * <tr><th>Event Name</th><th>Callback Type</th><th>Entity Event</th></tr> | |
| 911 | − * </thead> | |
| 912 | − * <tbody> | |
| 913 | − * <tr><td><code>"enterEntity"</code></td><td>{@link Script~entityEventCallback|entityEventCallback}</td> | |
| 914 | − * <td>{@link Entities.enterEntity}</td></tr> | |
| 915 | − * <tr><td><code>"leaveEntity"</code></td><td>{@link Script~entityEventCallback|entityEventCallback}</td> | |
| 916 | − * <td>{@link Entities.leaveEntity}</td></tr> | |
| 917 | − * <tr><td><code>"mousePressOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 918 | − * <td>{@link Entities.mousePressOnEntity}</td></tr> | |
| 919 | − * <tr><td><code>"mouseMoveOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 920 | − * <td>{@link Entities.mouseMoveOnEntity}</td></tr> | |
| 921 | − * <tr><td><code>"mouseReleaseOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 922 | − * <td>{@link Entities.mouseReleaseOnEntity}</td></tr> | |
| 923 | − * <tr><td><code>"clickDownOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 924 | − * <td>{@link Entities.clickDownOnEntity}</td></tr> | |
| 925 | − * <tr><td><code>"holdingClickOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 926 | − * <td>{@link Entities.holdingClickOnEntity}</td></tr> | |
| 927 | − * <tr><td><code>"clickReleaseOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 928 | − * <td>{@link Entities.clickReleaseOnEntity}</td></tr> | |
| 929 | − * <tr><td><code>"hoverEnterEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 930 | − * <td>{@link Entities.hoverEnterEntity}</td></tr> | |
| 931 | − * <tr><td><code>"hoverOverEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 932 | − * <td>{@link Entities.hoverOverEntity}</td></tr> | |
| 933 | − * <tr><td><code>"hoverLeaveEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td> | |
| 934 | − * <td>{@link Entities.hoverLeaveEntity}</td></tr> | |
| 935 | − * <tr><td><code>"collisionWithEntity"</code><td>{@link Script~collisionEventCallback|collisionEventCallback}</td> | |
| 936 | − * </td><td>{@link Entities.collisionWithEntity}</td></tr> | |
| 937 | − * </tbody> | |
| 938 | − * </table> | |
| 939 | − * @typedef {string} Script.EntityEvent | |
| 940 | − */ | |
| 941 | − connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); | |
| 942 | − connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); | |
| 943 | − | |
| 944 | − connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makePointerHandler("mousePressOnEntity")); | |
| 945 | − connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makePointerHandler("mouseMoveOnEntity")); | |
| 946 | − connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makePointerHandler("mouseReleaseOnEntity")); | |
| 947 | − | |
| 948 | − connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makePointerHandler("clickDownOnEntity")); | |
| 949 | − connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makePointerHandler("holdingClickOnEntity")); | |
| 950 | − connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makePointerHandler("clickReleaseOnEntity")); | |
| 951 | − | |
| 952 | − connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makePointerHandler("hoverEnterEntity")); | |
| 953 | − connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makePointerHandler("hoverOverEntity")); | |
| 954 | − connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makePointerHandler("hoverLeaveEntity")); | |
| 955 | − | |
| 956 | − connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity")); | |
| 788 | + if (_registeredHandlers.count() == 0) { | |
| 789 | + // First time any per-entity handler has been added in this script... | |
| 790 | + emit attachDefaultEventHandlers(); | |
| 957 | 791 | } |
| 958 | 792 | if (!_registeredHandlers.contains(entityID)) { |
| 959 | 793 | _registeredHandlers[entityID] = RegisteredEventHandlers(); |
| @@ -1008,9 +842,6 @@ void ScriptManager::run() { · 48 unmodified lines | ||
| 1008 | 842 | clock::time_point startTime = clock::now(); |
| 1009 | 843 | int thisFrame = 0; |
| 1010 | 844 | |
| 1011 | − auto nodeList = DependencyManager::get<NodeList>(); | |
| 1012 | − auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | |
| 1013 | − | |
| 1014 | 845 | _lastUpdate = usecTimestampNow(); |
| 1015 | 846 | |
| 1016 | 847 | std::chrono::microseconds totalUpdates(0); |
| @@ -1050,7 +881,7 @@ void ScriptManager::run() { · 33 unmodified lines | ||
| 1050 | 881 | QEventLoop loop; |
| 1051 | 882 | QTimer timer; |
| 1052 | 883 | timer.setSingleShot(true); |
| 1053 | − connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); | |
| 884 | + connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); | |
| 1054 | 885 | timer.start(sleepFor.count()); |
| 1055 | 886 | loop.exec(); |
| 1056 | 887 | } else { |
| @@ -1092,14 +923,8 @@ void ScriptManager::run() { · 35 unmodified lines | ||
| 1092 | 923 | break; |
| 1093 | 924 | } |
| 1094 | 925 | |
| 1095 | − if (!_isFinished && entityScriptingInterface->getEntityPacketSender()->serversExist()) { | |
| 1096 | − // release the queue of edit entity messages. | |
| 1097 | − entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); | |
| 1098 | − | |
| 1099 | − // since we're in non-threaded mode, call process so that the packets are sent | |
| 1100 | − if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) { | |
| 1101 | − entityScriptingInterface->getEntityPacketSender()->process(); | |
| 1102 | − } | |
| 926 | + if (!_isFinished) { | |
| 927 | + emit releaseEntityPacketSenderMessages(false); | |
| 1103 | 928 | } |
| 1104 | 929 | |
| 1105 | 930 | qint64 now = usecTimestampNow(); |
| @@ -1133,21 +958,7 @@ void ScriptManager::run() { · 27 unmodified lines | ||
| 1133 | 958 | stopAllTimers(); // make sure all our timers are stopped if the script is ending |
| 1134 | 959 | emit scriptEnding(); |
| 1135 | 960 | |
| 1136 | − if (entityScriptingInterface->getEntityPacketSender()->serversExist()) { | |
| 1137 | − // release the queue of edit entity messages. | |
| 1138 | − entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); | |
| 1139 | − | |
| 1140 | − // since we're in non-threaded mode, call process so that the packets are sent | |
| 1141 | − if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) { | |
| 1142 | − // wait here till the edit packet sender is completely done sending | |
| 1143 | − while (entityScriptingInterface->getEntityPacketSender()->hasPacketsToSend()) { | |
| 1144 | − entityScriptingInterface->getEntityPacketSender()->process(); | |
| 1145 | − QCoreApplication::processEvents(); | |
| 1146 | − } | |
| 1147 | − } else { | |
| 1148 | − // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders? | |
| 1149 | − } | |
| 1150 | − } | |
| 961 | + emit releaseEntityPacketSenderMessages(true); | |
| 1151 | 962 | |
| 1152 | 963 | emit finished(_fileNameString, qSharedPointerCast<ScriptManager>(sharedFromThis())); |
| 1153 | 964 | |
| @@ -1203,34 +1014,6 @@ void ScriptManager::stop(bool marshal) { · 49 unmodified lines | ||
| 1203 | 1014 | } |
| 1204 | 1015 | } |
| 1205 | 1016 | |
| 1206 | −// Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread. | |
| 1207 | −void ScriptManager::callAnimationStateHandler(ScriptValuePointer callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) { | |
| 1208 | − if (QThread::currentThread() != thread()) { | |
| 1209 | −#ifdef THREAD_DEBUGGING | |
| 1210 | − qCDebug(scriptengine) << "*** WARNING *** ScriptManager::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; | |
| 1211 | −#endif | |
| 1212 | − QMetaObject::invokeMethod(this, "callAnimationStateHandler", | |
| 1213 | − Q_ARG(ScriptValuePointer, callback), | |
| 1214 | − Q_ARG(AnimVariantMap, parameters), | |
| 1215 | − Q_ARG(QStringList, names), | |
| 1216 | − Q_ARG(bool, useNames), | |
| 1217 | − Q_ARG(AnimVariantResultHandler, resultHandler)); | |
| 1218 | − return; | |
| 1219 | − } | |
| 1220 | − ScriptValuePointer javascriptParameters = parameters.animVariantMapToScriptValue(_engine.get(), names, useNames); | |
| 1221 | − ScriptValueList callingArguments; | |
| 1222 | − callingArguments << javascriptParameters; | |
| 1223 | − assert(currentEntityIdentifier.isInvalidID()); // No animation state handlers from entity scripts. | |
| 1224 | − ScriptValuePointer result = callback->call(ScriptValuePointer(), callingArguments); | |
| 1225 | − | |
| 1226 | − // validate result from callback function. | |
| 1227 | − if (result->isValid() && result->isObject()) { | |
| 1228 | − resultHandler(result); | |
| 1229 | − } else { | |
| 1230 | − qCWarning(scriptengine) << "ScriptManager::callAnimationStateHandler invalid return argument from callback, expected an object"; | |
| 1231 | − } | |
| 1232 | −} | |
| 1233 | − | |
| 1234 | 1017 | void ScriptManager::updateMemoryCost(const qint64& deltaSize) { |
| 1235 | 1018 | _engine->updateMemoryCost(deltaSize); |
| 1236 | 1019 | } |