From ba2d93c2e9ae931e4c3dbc61a0a06b4329cd1625 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 25 Apr 2021 19:46:41 -0700 Subject: [PATCH 01/34] ensure all #include's to QtScript are labeled as such (easier to find) --- interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/scripting/AccountServicesScriptingInterface.h | 6 +++--- interface/src/scripting/WindowScriptingInterface.cpp | 2 +- interface/src/ui/overlays/Overlays.h | 2 +- libraries/animation/src/AnimVariant.cpp | 4 ++-- libraries/animation/src/AnimVariant.h | 2 +- libraries/animation/src/AnimationObject.cpp | 2 +- libraries/animation/src/AnimationObject.h | 2 +- libraries/animation/src/Rig.cpp | 2 +- libraries/animation/src/Rig.h | 2 +- libraries/audio/src/AudioInjectorOptions.cpp | 2 +- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- libraries/entities/src/EntityEditFilters.h | 4 ++-- libraries/entities/src/EntityItemID.h | 2 +- .../model-networking/src/model-networking/SimpleMeshProxy.h | 4 ++-- libraries/networking/src/LocationScriptingInterface.h | 2 +- libraries/networking/src/ResourceCache.h | 2 +- libraries/script-engine/src/ArrayBufferClass.h | 2 +- libraries/script-engine/src/ArrayBufferViewClass.h | 2 +- libraries/script-engine/src/EventTypes.h | 2 +- libraries/script-engine/src/KeyEvent.cpp | 2 +- libraries/script-engine/src/KeyEvent.h | 2 +- libraries/script-engine/src/ModelScriptingInterface.cpp | 4 ++-- libraries/script-engine/src/MouseEvent.cpp | 4 ++-- libraries/script-engine/src/MouseEvent.h | 2 +- libraries/script-engine/src/SceneScriptingInterface.h | 2 +- libraries/script-engine/src/SpatialEvent.h | 2 +- libraries/script-engine/src/TouchEvent.cpp | 4 ++-- libraries/script-engine/src/WebSocketClass.h | 2 +- libraries/script-engine/src/WebSocketServerClass.h | 2 +- libraries/script-engine/src/WheelEvent.cpp | 4 ++-- libraries/script-engine/src/XMLHttpRequestClass.h | 6 +++--- libraries/shared/src/PointerEvent.cpp | 4 ++-- libraries/shared/src/PointerEvent.h | 2 +- libraries/shared/src/ScriptValueUtils.h | 2 +- libraries/shared/src/VariantMapToScriptValue.h | 4 ++-- 36 files changed, 49 insertions(+), 49 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e4b7176a011..b119f21f17b 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -13,7 +13,7 @@ #include -#include +#include #include "AvatarLogging.h" diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index 288137e1664..7336d3e5cc9 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -13,9 +13,9 @@ #define hifi_AccountServicesScriptingInterface_h #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 98335e5d3ad..c34d1ac0066 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index a6d4414bec1..6e59cbc00e9 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index eb9e595c88e..1519aa8109e 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -11,8 +11,8 @@ #include "AnimVariant.h" // which has AnimVariant/AnimVariantMap -#include -#include +#include +#include #include #include diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index a8bdb885e54..d9e75d5844f 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include "AnimationLogging.h" diff --git a/libraries/animation/src/AnimationObject.cpp b/libraries/animation/src/AnimationObject.cpp index bcbf4971995..831f310beec 100644 --- a/libraries/animation/src/AnimationObject.cpp +++ b/libraries/animation/src/AnimationObject.cpp @@ -11,7 +11,7 @@ #include "AnimationObject.h" -#include +#include #include "AnimationCache.h" diff --git a/libraries/animation/src/AnimationObject.h b/libraries/animation/src/AnimationObject.h index 40fd534a71d..9df58a20afb 100644 --- a/libraries/animation/src/AnimationObject.h +++ b/libraries/animation/src/AnimationObject.h @@ -13,7 +13,7 @@ #define hifi_AnimationObject_h #include -#include +#include #include diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 6dc378a32f0..e0589fdba98 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index c58be799cfe..7ae48a90ee9 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index cb7da4de336..99a2886a77c 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -11,7 +11,7 @@ #include "AudioInjectorOptions.h" -#include +#include #include diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 949ad85945b..1504afdebee 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/libraries/entities/src/EntityEditFilters.h b/libraries/entities/src/EntityEditFilters.h index 69fd9209981..d1cef0c5f09 100644 --- a/libraries/entities/src/EntityEditFilters.h +++ b/libraries/entities/src/EntityEditFilters.h @@ -13,8 +13,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/libraries/entities/src/EntityItemID.h b/libraries/entities/src/EntityItemID.h index c9ffa13941c..5ff58ede362 100644 --- a/libraries/entities/src/EntityItemID.h +++ b/libraries/entities/src/EntityItemID.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include const QUuid UNKNOWN_ENTITY_ID; // null uuid diff --git a/libraries/model-networking/src/model-networking/SimpleMeshProxy.h b/libraries/model-networking/src/model-networking/SimpleMeshProxy.h index 073eb1c00fc..9282557a4fb 100644 --- a/libraries/model-networking/src/model-networking/SimpleMeshProxy.h +++ b/libraries/model-networking/src/model-networking/SimpleMeshProxy.h @@ -12,8 +12,8 @@ #ifndef hifi_SimpleMeshProxy_h #define hifi_SimpleMeshProxy_h -#include -#include +#include +#include #include #include diff --git a/libraries/networking/src/LocationScriptingInterface.h b/libraries/networking/src/LocationScriptingInterface.h index 987c4ccd0d3..f1086ffa600 100644 --- a/libraries/networking/src/LocationScriptingInterface.h +++ b/libraries/networking/src/LocationScriptingInterface.h @@ -12,7 +12,7 @@ #ifndef hifi_LocationScriptingInterface_h #define hifi_LocationScriptingInterface_h -#include +#include class LocationScriptingInterface : public QObject { Q_OBJECT diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 4d5e8964ce2..73af38fd369 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -28,7 +28,7 @@ #include #include -#include +#include #include diff --git a/libraries/script-engine/src/ArrayBufferClass.h b/libraries/script-engine/src/ArrayBufferClass.h index 295b9c3fa42..3255ab30e70 100644 --- a/libraries/script-engine/src/ArrayBufferClass.h +++ b/libraries/script-engine/src/ArrayBufferClass.h @@ -12,7 +12,7 @@ #ifndef hifi_ArrayBufferClass_h #define hifi_ArrayBufferClass_h -#include +#include #include #include #include diff --git a/libraries/script-engine/src/ArrayBufferViewClass.h b/libraries/script-engine/src/ArrayBufferViewClass.h index 67af4a3fc3b..a1f7f8245fa 100644 --- a/libraries/script-engine/src/ArrayBufferViewClass.h +++ b/libraries/script-engine/src/ArrayBufferViewClass.h @@ -12,7 +12,7 @@ #ifndef hifi_ArrayBufferViewClass_h #define hifi_ArrayBufferViewClass_h -#include +#include #include #include #include diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 906006e4f44..146ab338d61 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -12,7 +12,7 @@ #ifndef hifi_EventTypes_h #define hifi_EventTypes_h -#include +#include void registerEventTypes(QScriptEngine* engine); diff --git a/libraries/script-engine/src/KeyEvent.cpp b/libraries/script-engine/src/KeyEvent.cpp index b0e622a7747..1887486054f 100644 --- a/libraries/script-engine/src/KeyEvent.cpp +++ b/libraries/script-engine/src/KeyEvent.cpp @@ -12,7 +12,7 @@ #include "KeyEvent.h" #include -#include +#include #include "ScriptEngineLogging.h" diff --git a/libraries/script-engine/src/KeyEvent.h b/libraries/script-engine/src/KeyEvent.h index 350b733eafa..4d66192a74f 100644 --- a/libraries/script-engine/src/KeyEvent.h +++ b/libraries/script-engine/src/KeyEvent.h @@ -13,7 +13,7 @@ #define hifi_KeyEvent_h #include -#include +#include class KeyEvent { public: diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index 1716ea72ffc..2e9a9ca14a9 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -10,8 +10,8 @@ // #include "ModelScriptingInterface.h" -#include -#include +#include +#include #include #include #include "ScriptEngine.h" diff --git a/libraries/script-engine/src/MouseEvent.cpp b/libraries/script-engine/src/MouseEvent.cpp index 1bace0425fd..f3a5cb80c05 100644 --- a/libraries/script-engine/src/MouseEvent.cpp +++ b/libraries/script-engine/src/MouseEvent.cpp @@ -11,8 +11,8 @@ #include "MouseEvent.h" -#include -#include +#include +#include MouseEvent::MouseEvent() : x(0.0f), diff --git a/libraries/script-engine/src/MouseEvent.h b/libraries/script-engine/src/MouseEvent.h index d9b00a8e019..04e474366d6 100644 --- a/libraries/script-engine/src/MouseEvent.h +++ b/libraries/script-engine/src/MouseEvent.h @@ -13,7 +13,7 @@ #define hifi_MouseEvent_h #include -#include +#include class QScriptEngine; diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index ce205bdf3ce..66c3f2ee96c 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -12,7 +12,7 @@ #ifndef hifi_SceneScriptingInterface_h #define hifi_SceneScriptingInterface_h -#include +#include #include /**jsdoc diff --git a/libraries/script-engine/src/SpatialEvent.h b/libraries/script-engine/src/SpatialEvent.h index e0fcc038240..9063e487969 100644 --- a/libraries/script-engine/src/SpatialEvent.h +++ b/libraries/script-engine/src/SpatialEvent.h @@ -15,7 +15,7 @@ #include #include -#include +#include class SpatialEvent { public: diff --git a/libraries/script-engine/src/TouchEvent.cpp b/libraries/script-engine/src/TouchEvent.cpp index 58ac9ec8c16..050fe8b0fd2 100644 --- a/libraries/script-engine/src/TouchEvent.cpp +++ b/libraries/script-engine/src/TouchEvent.cpp @@ -11,8 +11,8 @@ #include "TouchEvent.h" -#include -#include +#include +#include #include diff --git a/libraries/script-engine/src/WebSocketClass.h b/libraries/script-engine/src/WebSocketClass.h index 3430068eee3..a3faaadbb59 100644 --- a/libraries/script-engine/src/WebSocketClass.h +++ b/libraries/script-engine/src/WebSocketClass.h @@ -13,7 +13,7 @@ #define hifi_WebSocketClass_h #include -#include +#include #include /**jsdoc diff --git a/libraries/script-engine/src/WebSocketServerClass.h b/libraries/script-engine/src/WebSocketServerClass.h index fff33d5bfbb..a78e8544a3c 100644 --- a/libraries/script-engine/src/WebSocketServerClass.h +++ b/libraries/script-engine/src/WebSocketServerClass.h @@ -13,7 +13,7 @@ #define hifi_WebSocketServerClass_h #include -#include +#include #include #include "WebSocketClass.h" diff --git a/libraries/script-engine/src/WheelEvent.cpp b/libraries/script-engine/src/WheelEvent.cpp index a0a897c991a..2bc321691f1 100644 --- a/libraries/script-engine/src/WheelEvent.cpp +++ b/libraries/script-engine/src/WheelEvent.cpp @@ -11,8 +11,8 @@ #include "WheelEvent.h" -#include -#include +#include +#include WheelEvent::WheelEvent() : x(0.0f), diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h index 3ab7d38dda0..01127e786db 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.h +++ b/libraries/script-engine/src/XMLHttpRequestClass.h @@ -16,9 +16,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include /* diff --git a/libraries/shared/src/PointerEvent.cpp b/libraries/shared/src/PointerEvent.cpp index 54374a934c0..6882efd5886 100644 --- a/libraries/shared/src/PointerEvent.cpp +++ b/libraries/shared/src/PointerEvent.cpp @@ -11,8 +11,8 @@ #include "PointerEvent.h" -#include -#include +#include +#include #include "RegisteredMetaTypes.h" diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index 23f435a67c7..ea774aa67b1 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -16,7 +16,7 @@ #include #include -#include +#include class PointerEvent { public: diff --git a/libraries/shared/src/ScriptValueUtils.h b/libraries/shared/src/ScriptValueUtils.h index 2e120a7217a..dc2f41997b4 100644 --- a/libraries/shared/src/ScriptValueUtils.h +++ b/libraries/shared/src/ScriptValueUtils.h @@ -14,7 +14,7 @@ #ifndef hifi_ScriptValueUtils_h #define hifi_ScriptValueUtils_h -#include +#include bool isListOfStrings(const QScriptValue& value); diff --git a/libraries/shared/src/VariantMapToScriptValue.h b/libraries/shared/src/VariantMapToScriptValue.h index ea65cccb3d4..4b283671b43 100644 --- a/libraries/shared/src/VariantMapToScriptValue.h +++ b/libraries/shared/src/VariantMapToScriptValue.h @@ -10,8 +10,8 @@ // #include -#include -#include +#include +#include QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine); QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine); From 5e36015b7bee0940425ea1cf099ec8033ad169e3 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 16 May 2021 00:01:05 -0700 Subject: [PATCH 02/34] isolate calls to the QtScript libraries to an interface we control --- assignment-client/CMakeLists.txt | 2 +- assignment-client/src/Agent.cpp | 44 +- assignment-client/src/Agent.h | 10 +- .../src/avatars/ScriptableAvatar.cpp | 10 +- .../src/avatars/ScriptableAvatar.h | 2 +- .../src/scripts/EntityScriptServer.cpp | 73 +- .../src/scripts/EntityScriptServer.h | 6 +- domain-server/CMakeLists.txt | 1 + interface/CMakeLists.txt | 7 +- interface/src/Application.cpp | 52 +- interface/src/Application.h | 7 +- interface/src/AvatarBookmarks.cpp | 10 +- interface/src/LODManager.cpp | 8 +- interface/src/LODManager.h | 8 +- interface/src/Menu.cpp | 1 + interface/src/avatar/AvatarManager.cpp | 13 +- interface/src/avatar/AvatarManager.h | 12 +- interface/src/avatar/MyAvatar.cpp | 43 +- interface/src/avatar/MyAvatar.h | 20 +- .../LaserPointerScriptingInterface.cpp | 6 +- .../raypick/LaserPointerScriptingInterface.h | 8 +- interface/src/raypick/PathPointer.cpp | 1 + .../src/raypick/PickScriptingInterface.cpp | 24 +- .../src/raypick/PickScriptingInterface.h | 11 +- .../src/raypick/PointerScriptingInterface.cpp | 6 +- .../src/raypick/PointerScriptingInterface.h | 8 +- .../src/raypick/RayPickScriptingInterface.cpp | 5 +- .../src/raypick/RayPickScriptingInterface.h | 8 +- .../AccountServicesScriptingInterface.cpp | 18 +- .../AccountServicesScriptingInterface.h | 12 +- .../AssetMappingsScriptingInterface.cpp | 2 +- .../AssetMappingsScriptingInterface.h | 2 - .../src/scripting/DesktopScriptingInterface.h | 1 - .../src/scripting/HMDScriptingInterface.cpp | 17 +- .../src/scripting/HMDScriptingInterface.h | 14 +- .../PlatformInfoScriptingInterface.h | 2 - .../scripting/SettingsScriptingInterface.cpp | 2 +- .../src/scripting/TestScriptingInterface.cpp | 5 +- .../src/scripting/TestScriptingInterface.h | 6 +- .../scripting/WindowScriptingInterface.cpp | 49 +- .../src/scripting/WindowScriptingInterface.h | 23 +- interface/src/ui/InteractiveWindow.cpp | 14 +- interface/src/ui/InteractiveWindow.h | 12 +- interface/src/ui/JSConsole.cpp | 58 +- interface/src/ui/JSConsole.h | 15 +- interface/src/ui/TestingDialog.cpp | 11 +- interface/src/ui/TestingDialog.h | 7 +- interface/src/ui/overlays/Overlays.cpp | 68 +- interface/src/ui/overlays/Overlays.h | 15 +- libraries/animation/CMakeLists.txt | 8 +- libraries/animation/src/AnimVariant.cpp | 82 +- libraries/animation/src/AnimVariant.h | 12 +- libraries/animation/src/AnimationCache.h | 2 - libraries/animation/src/AnimationObject.cpp | 18 +- libraries/animation/src/AnimationObject.h | 10 +- libraries/animation/src/Rig.cpp | 32 +- libraries/animation/src/Rig.h | 12 +- libraries/audio/CMakeLists.txt | 2 +- libraries/audio/src/AudioEffectOptions.cpp | 12 +- libraries/audio/src/AudioEffectOptions.h | 12 +- libraries/audio/src/AudioInjectorOptions.cpp | 82 +- libraries/audio/src/AudioInjectorOptions.h | 11 +- libraries/audio/src/Sound.cpp | 10 +- libraries/audio/src/Sound.h | 9 +- libraries/avatars-renderer/CMakeLists.txt | 19 +- libraries/avatars/CMakeLists.txt | 4 +- libraries/avatars/src/AvatarData.cpp | 106 +- libraries/avatars/src/AvatarData.h | 20 +- libraries/baking/CMakeLists.txt | 2 +- libraries/baking/src/MaterialBaker.cpp | 7 +- libraries/baking/src/MaterialBaker.h | 3 +- libraries/controllers/CMakeLists.txt | 4 +- .../controllers/src/controllers/Pose.cpp | 37 +- libraries/controllers/src/controllers/Pose.h | 10 +- .../src/controllers/ScriptingInterface.h | 1 - .../src/controllers/UserInputMapper.cpp | 120 +- .../src/controllers/UserInputMapper.h | 12 +- .../src/controllers/impl/Endpoint.h | 2 - .../src/controllers/impl/Filter.cpp | 1 - .../controllers/impl/MappingBuilderProxy.cpp | 7 +- .../controllers/impl/MappingBuilderProxy.h | 8 +- .../controllers/impl/RouteBuilderProxy.cpp | 7 +- .../src/controllers/impl/RouteBuilderProxy.h | 8 +- .../impl/conditionals/ScriptConditional.cpp | 4 +- .../impl/conditionals/ScriptConditional.h | 10 +- .../impl/endpoints/ScriptEndpoint.cpp | 38 +- .../impl/endpoints/ScriptEndpoint.h | 9 +- libraries/entities-renderer/CMakeLists.txt | 20 +- .../src/EntityTreeRenderer.cpp | 144 +- .../src/EntityTreeRenderer.h | 13 +- libraries/entities/CMakeLists.txt | 5 +- .../src/AmbientLightPropertyGroup.cpp | 6 +- .../entities/src/AmbientLightPropertyGroup.h | 11 +- .../entities/src/AnimationPropertyGroup.cpp | 4 +- .../entities/src/AnimationPropertyGroup.h | 12 +- libraries/entities/src/BloomPropertyGroup.cpp | 4 +- libraries/entities/src/BloomPropertyGroup.h | 11 +- libraries/entities/src/EntityEditFilters.cpp | 142 +- libraries/entities/src/EntityEditFilters.h | 15 +- libraries/entities/src/EntityItemID.cpp | 16 +- libraries/entities/src/EntityItemID.h | 14 +- .../entities/src/EntityItemProperties.cpp | 137 +- libraries/entities/src/EntityItemProperties.h | 38 +- .../entities/src/EntityItemPropertiesMacros.h | 225 +-- .../entities/src/EntityScriptingInterface.cpp | 180 +-- .../entities/src/EntityScriptingInterface.h | 46 +- libraries/entities/src/EntityTree.cpp | 18 +- libraries/entities/src/GrabPropertyGroup.cpp | 6 +- libraries/entities/src/GrabPropertyGroup.h | 10 +- libraries/entities/src/HazePropertyGroup.cpp | 4 +- libraries/entities/src/HazePropertyGroup.h | 11 +- .../entities/src/KeyLightPropertyGroup.cpp | 6 +- .../entities/src/KeyLightPropertyGroup.h | 11 +- libraries/entities/src/PropertyGroup.h | 9 +- libraries/entities/src/PulsePropertyGroup.cpp | 6 +- libraries/entities/src/PulsePropertyGroup.h | 11 +- .../src/RecurseOctreeToJSONOperator.cpp | 9 +- .../src/RecurseOctreeToJSONOperator.h | 12 +- .../src/RecurseOctreeToMapOperator.cpp | 9 +- .../entities/src/RecurseOctreeToMapOperator.h | 6 +- .../entities/src/RingGizmoPropertyGroup.cpp | 6 +- .../entities/src/RingGizmoPropertyGroup.h | 11 +- .../entities/src/SkyboxPropertyGroup.cpp | 4 +- libraries/entities/src/SkyboxPropertyGroup.h | 11 +- .../src/graphics-scripting/Forward.h | 1 - .../GraphicsScriptingInterface.cpp | 189 +-- .../GraphicsScriptingInterface.h | 14 +- .../GraphicsScriptingUtil.cpp | 23 +- .../GraphicsScriptingUtil.h | 13 +- .../src/graphics-scripting/ScriptableMesh.cpp | 42 +- .../src/graphics-scripting/ScriptableMesh.h | 21 +- .../graphics-scripting/ScriptableMeshPart.cpp | 7 +- .../graphics-scripting/ScriptableMeshPart.h | 16 +- .../graphics-scripting/ScriptableModel.cpp | 4 +- .../src/graphics-scripting/ScriptableModel.h | 2 - .../src/model-networking/SimpleMeshProxy.h | 4 - libraries/networking/CMakeLists.txt | 1 + libraries/networking/src/AssetClient.cpp | 1 - .../src/BaseAssetScriptingInterface.h | 2 +- .../src/LocationScriptingInterface.cpp | 11 +- .../src/LocationScriptingInterface.h | 11 +- libraries/networking/src/ResourceCache.h | 10 +- libraries/physics/CMakeLists.txt | 1 + libraries/pointers/CMakeLists.txt | 2 +- libraries/recording/CMakeLists.txt | 2 +- libraries/render-utils/CMakeLists.txt | 2 +- libraries/render-utils/src/Model.h | 1 - .../script-engine-qtscript/CMakeLists.txt | 10 + .../src/ArrayBufferClass.h | 4 +- .../src/ArrayBufferPrototype.cpp | 4 +- .../src/ArrayBufferPrototype.h | 0 .../src/ArrayBufferViewClass.cpp | 5 +- .../src/ArrayBufferViewClass.h | 8 +- .../src/BaseScriptEngine.cpp | 41 +- .../src/BaseScriptEngine.h | 41 +- .../src/DataViewClass.cpp | 2 +- .../src/DataViewClass.h | 2 +- .../src/DataViewPrototype.cpp | 3 + .../src/DataViewPrototype.h | 0 .../src/ScriptEngineQtScript.cpp | 493 +++++++ .../src/ScriptEngineQtScript.h | 397 ++++++ .../src/TypedArrayPrototype.cpp | 2 + .../src/TypedArrayPrototype.h | 4 +- .../src/TypedArrays.cpp | 27 +- .../src/TypedArrays.h | 20 +- libraries/script-engine/CMakeLists.txt | 22 +- .../src/AbstractScriptingServicesInterface.h | 7 +- .../script-engine/src/ArrayBufferClass.cpp | 180 --- .../src/AssetScriptingInterface.cpp | 159 ++- .../src/AssetScriptingInterface.h | 51 +- .../src/AudioScriptingInterface.cpp | 8 +- .../src/AudioScriptingInterface.h | 3 +- .../src/ConsoleScriptingInterface.cpp | 114 +- .../src/ConsoleScriptingInterface.h | 35 +- libraries/script-engine/src/EventTypes.cpp | 18 +- libraries/script-engine/src/EventTypes.h | 4 +- libraries/script-engine/src/KeyEvent.cpp | 53 +- libraries/script-engine/src/KeyEvent.h | 10 +- libraries/script-engine/src/MIDIEvent.cpp | 32 +- libraries/script-engine/src/MIDIEvent.h | 14 +- libraries/script-engine/src/Mat4.cpp | 5 +- libraries/script-engine/src/Mat4.h | 4 +- .../script-engine/src/MenuItemProperties.cpp | 43 +- .../script-engine/src/MenuItemProperties.h | 13 +- .../src/ModelScriptingInterface.cpp | 48 +- .../src/ModelScriptingInterface.h | 19 +- libraries/script-engine/src/MouseEvent.cpp | 30 +- libraries/script-engine/src/MouseEvent.h | 12 +- .../src/PointerEvent.cpp | 118 +- .../src/PointerEvent.h | 12 +- libraries/script-engine/src/Quat.cpp | 5 +- libraries/script-engine/src/Quat.h | 5 +- .../src/RecordingScriptingInterface.cpp | 56 +- .../src/RecordingScriptingInterface.h | 12 +- .../src/SceneScriptingInterface.h | 1 - .../script-engine/src/ScriptAudioInjector.cpp | 12 +- .../script-engine/src/ScriptAudioInjector.h | 11 +- libraries/script-engine/src/ScriptContext.h | 53 + libraries/script-engine/src/ScriptEngine.h | 1113 ++------------- .../script-engine/src/ScriptEngineCast.h | 99 ++ libraries/script-engine/src/ScriptEngines.cpp | 153 +- libraries/script-engine/src/ScriptEngines.h | 38 +- .../{ScriptEngine.cpp => ScriptManager.cpp} | 1241 ++++++++--------- libraries/script-engine/src/ScriptManager.h | 961 +++++++++++++ libraries/script-engine/src/ScriptProgram.h | 45 + libraries/script-engine/src/ScriptUUID.cpp | 5 +- libraries/script-engine/src/ScriptUUID.h | 5 +- libraries/script-engine/src/ScriptValue.h | 206 +++ .../script-engine/src/ScriptValueIterator.h | 32 + .../script-engine/src/ScriptValueUtils.cpp | 888 ++++++++++++ .../script-engine/src/ScriptValueUtils.h | 262 ++++ libraries/script-engine/src/Scriptable.h | 59 + libraries/script-engine/src/ScriptsModel.h | 7 +- libraries/script-engine/src/SpatialEvent.cpp | 17 +- libraries/script-engine/src/SpatialEvent.h | 9 +- libraries/script-engine/src/TouchEvent.cpp | 66 +- libraries/script-engine/src/TouchEvent.h | 10 +- .../src/VariantMapToScriptValue.cpp | 26 +- .../src/VariantMapToScriptValue.h | 18 + libraries/script-engine/src/Vec3.cpp | 5 +- libraries/script-engine/src/Vec3.h | 4 +- .../script-engine/src/WebSocketClass.cpp | 96 +- libraries/script-engine/src/WebSocketClass.h | 61 +- .../src/WebSocketServerClass.cpp | 24 +- .../script-engine/src/WebSocketServerClass.h | 13 +- libraries/script-engine/src/WheelEvent.cpp | 32 +- libraries/script-engine/src/WheelEvent.h | 10 +- .../script-engine/src/XMLHttpRequestClass.cpp | 55 +- .../script-engine/src/XMLHttpRequestClass.h | 62 +- libraries/shared/CMakeLists.txt | 2 +- libraries/shared/src/RegisteredMetaTypes.cpp | 831 ----------- libraries/shared/src/RegisteredMetaTypes.h | 100 -- libraries/shared/src/ScriptValueUtils.cpp | 34 - libraries/shared/src/ScriptValueUtils.h | 21 - .../shared/src/VariantMapToScriptValue.h | 18 - libraries/shared/src/shared/MiniPromises.cpp | 15 - libraries/shared/src/shared/MiniPromises.h | 1 - .../src/shared/ScriptInitializerMixin.h | 7 +- libraries/ui/CMakeLists.txt | 6 +- libraries/ui/src/QmlFragmentClass.cpp | 21 +- libraries/ui/src/QmlFragmentClass.h | 14 +- libraries/ui/src/QmlWebWindowClass.cpp | 10 +- libraries/ui/src/QmlWebWindowClass.h | 13 +- libraries/ui/src/QmlWindowClass.cpp | 31 +- libraries/ui/src/QmlWindowClass.h | 18 +- libraries/ui/src/ui/QmlWrapper.h | 15 +- .../ui/src/ui/TabletScriptingInterface.h | 4 - .../ui/src/ui/ToolbarScriptingInterface.cpp | 20 +- .../ui/src/ui/ToolbarScriptingInterface.h | 1 - plugins/JSAPIExample/CMakeLists.txt | 5 +- plugins/JSAPIExample/src/JSAPIExample.cpp | 39 +- plugins/hifiSdl2/CMakeLists.txt | 3 +- plugins/openvr/CMakeLists.txt | 3 +- scripts/system/request-service.js | 2 +- tests-manual/controllers/CMakeLists.txt | 2 +- tests-manual/entities/CMakeLists.txt | 2 +- tests-manual/gpu-textures/CMakeLists.txt | 2 +- tests-manual/gpu/CMakeLists.txt | 2 +- tests/octree/CMakeLists.txt | 2 +- tests/physics/CMakeLists.txt | 2 +- tools/oven/CMakeLists.txt | 1 + 261 files changed, 6928 insertions(+), 5268 deletions(-) create mode 100644 libraries/script-engine-qtscript/CMakeLists.txt rename libraries/{script-engine => script-engine-qtscript}/src/ArrayBufferClass.h (95%) rename libraries/{script-engine => script-engine-qtscript}/src/ArrayBufferPrototype.cpp (98%) rename libraries/{script-engine => script-engine-qtscript}/src/ArrayBufferPrototype.h (100%) rename libraries/{script-engine => script-engine-qtscript}/src/ArrayBufferViewClass.cpp (92%) rename libraries/{script-engine => script-engine-qtscript}/src/ArrayBufferViewClass.h (88%) rename libraries/{shared => script-engine-qtscript}/src/BaseScriptEngine.cpp (88%) rename libraries/{shared => script-engine-qtscript}/src/BaseScriptEngine.h (66%) rename libraries/{script-engine => script-engine-qtscript}/src/DataViewClass.cpp (97%) rename libraries/{script-engine => script-engine-qtscript}/src/DataViewClass.h (93%) rename libraries/{script-engine => script-engine-qtscript}/src/DataViewPrototype.cpp (99%) rename libraries/{script-engine => script-engine-qtscript}/src/DataViewPrototype.h (100%) create mode 100644 libraries/script-engine-qtscript/src/ScriptEngineQtScript.cpp create mode 100644 libraries/script-engine-qtscript/src/ScriptEngineQtScript.h rename libraries/{script-engine => script-engine-qtscript}/src/TypedArrayPrototype.cpp (99%) rename libraries/{script-engine => script-engine-qtscript}/src/TypedArrayPrototype.h (89%) rename libraries/{script-engine => script-engine-qtscript}/src/TypedArrays.cpp (92%) rename libraries/{script-engine => script-engine-qtscript}/src/TypedArrays.h (89%) delete mode 100644 libraries/script-engine/src/ArrayBufferClass.cpp rename libraries/{shared => script-engine}/src/PointerEvent.cpp (72%) rename libraries/{shared => script-engine}/src/PointerEvent.h (89%) create mode 100644 libraries/script-engine/src/ScriptContext.h create mode 100644 libraries/script-engine/src/ScriptEngineCast.h rename libraries/script-engine/src/{ScriptEngine.cpp => ScriptManager.cpp} (66%) create mode 100644 libraries/script-engine/src/ScriptManager.h create mode 100644 libraries/script-engine/src/ScriptProgram.h create mode 100644 libraries/script-engine/src/ScriptValue.h create mode 100644 libraries/script-engine/src/ScriptValueIterator.h create mode 100644 libraries/script-engine/src/ScriptValueUtils.cpp create mode 100644 libraries/script-engine/src/ScriptValueUtils.h create mode 100644 libraries/script-engine/src/Scriptable.h rename libraries/{shared => script-engine}/src/VariantMapToScriptValue.cpp (61%) create mode 100644 libraries/script-engine/src/VariantMapToScriptValue.h delete mode 100644 libraries/shared/src/ScriptValueUtils.cpp delete mode 100644 libraries/shared/src/ScriptValueUtils.h delete mode 100644 libraries/shared/src/VariantMapToScriptValue.h diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index abb94f95e3c..345118a89b0 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME assignment-client) -setup_hifi_project(Core Gui Network Script Quick WebSockets) +setup_hifi_project(Core Gui Network Quick WebSockets) # Fix up the rpath so macdeployqt works if (APPLE) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index a8ce7e30e59..1512c27d365 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -180,7 +183,7 @@ static const QString AGENT_LOGGING_NAME = "agent"; void Agent::run() { // Create ScriptEngines on threaded-assignment thread then move to main thread. - DependencyManager::set(ScriptEngine::AGENT_SCRIPT)->moveToThread(qApp->thread()); + DependencyManager::set(ScriptManager::AGENT_SCRIPT)->moveToThread(qApp->thread()); DependencyManager::set(); @@ -372,7 +375,7 @@ void Agent::executeScript() { // the following block is scoped so that any shared pointers we take here // are cleared before we call setFinished at the end of the function { - _scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload); + _scriptManager = scriptManagerFactory(ScriptManager::AGENT_SCRIPT, _scriptContents, _payload); // setup an Avatar for the script to use auto scriptedAvatar = DependencyManager::get(); @@ -386,10 +389,11 @@ void Agent::executeScript() { scriptedAvatar->getHeadOrientation(); // give this AvatarData object to the script engine - _scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data()); + auto scriptEngine = _scriptManager->engine(); + scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data()); // give scripts access to the Users object - _scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); auto player = DependencyManager::get(); connect(player.data(), &recording::Deck::playbackStateChanged, [&player, &scriptedAvatar] { @@ -493,26 +497,26 @@ void Agent::executeScript() { }); auto avatarHashMap = DependencyManager::set(); - _scriptEngine->registerGlobalObject("AvatarList", avatarHashMap.data()); + scriptEngine->registerGlobalObject("AvatarList", avatarHashMap.data()); // register ourselves to the script engine - _scriptEngine->registerGlobalObject("Agent", new AgentScriptingInterface(this)); + scriptEngine->registerGlobalObject("Agent", new AgentScriptingInterface(this)); - _scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); - _scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); - QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor); - _scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); + ScriptValuePointer webSocketServerConstructorValue = scriptEngine->newFunction(WebSocketServerClass::constructor); + scriptEngine->globalObject()->setProperty("WebSocketServer", webSocketServerConstructorValue); auto entityScriptingInterface = DependencyManager::get(); - _scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer); + scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer); - _scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, + scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter); auto recordingInterface = DependencyManager::get(); - _scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); + scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); entityScriptingInterface->init(); @@ -522,8 +526,8 @@ void Agent::executeScript() { DependencyManager::set(_entityViewer.getTree()); - DependencyManager::get()->runScriptInitializers(_scriptEngine); - _scriptEngine->run(); + DependencyManager::get()->runScriptInitializers(_scriptManager); + _scriptManager->run(); Frame::clearFrameHandler(AUDIO_FRAME_TYPE); Frame::clearFrameHandler(AVATAR_FRAME_TYPE); @@ -602,7 +606,7 @@ void Agent::setIsAvatar(bool isAvatar) { // start the timer _avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS); - connect(_scriptEngine.data(), &ScriptEngine::update, + connect(_scriptManager.data(), &ScriptManager::update, scriptableAvatar.data(), &ScriptableAvatar::update, Qt::QueuedConnection); // tell the avatarAudioTimer to start ticking @@ -638,7 +642,7 @@ void Agent::setIsAvatar(bool isAvatar) { nodeList->sendPacket(std::move(packet), *node); }); - disconnect(_scriptEngine.data(), &ScriptEngine::update, + disconnect(_scriptManager.data(), &ScriptManager::update, scriptableAvatar.data(), &ScriptableAvatar::update); QMetaObject::invokeMethod(&_avatarAudioTimer, "stop"); @@ -875,7 +879,7 @@ void Agent::aboutToFinish() { // drop our shared pointer to the script engine, then ask ScriptEngines to shutdown scripting // this ensures that the ScriptEngine goes down before ScriptEngines - _scriptEngine.clear(); + _scriptManager.clear(); { DependencyManager::get()->shutdownScripting(); @@ -895,8 +899,8 @@ void Agent::aboutToFinish() { } void Agent::stop() { - if (_scriptEngine) { - _scriptEngine->stop(); + if (_scriptManager) { + _scriptManager->stop(); } else { setFinished(true); } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index b8e7652ccac..d3ed93e3560 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -15,11 +15,11 @@ #include #include -#include #include #include #include #include +#include #include #include @@ -28,11 +28,17 @@ #include +#include #include "AudioGate.h" #include "MixedAudioStream.h" #include "entities/EntityTreeHeadlessViewer.h" #include "avatars/ScriptableAvatar.h" +class ScriptEngine; +class ScriptManager; +using ScriptEnginePointer = QSharedPointer; +using ScriptManagerPointer = QSharedPointer; + class Agent : public ThreadedAssignment { Q_OBJECT @@ -89,7 +95,7 @@ private slots: void encodeFrameOfZeros(QByteArray& encodedZeros); void computeLoudness(const QByteArray* decodedBuffer, QSharedPointer); - ScriptEnginePointer _scriptEngine; + ScriptManagerPointer _scriptManager; EntityEditPacketSender _entityEditSender; EntityTreeHeadlessViewer _entityViewer; diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 752eaf81d28..15c9fce788d 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -17,16 +17,18 @@ #include #include +#include #include #include #include #include #include #include +#include #include -ScriptableAvatar::ScriptableAvatar() { +ScriptableAvatar::ScriptableAvatar(): _scriptEngine(newScriptEngine()) { _clientTraitsHandler.reset(new ClientTraitsHandler(this)); } @@ -311,7 +313,7 @@ AvatarEntityMap ScriptableAvatar::getAvatarEntityDataInternal(bool allProperties EntityItemProperties properties = entity->getProperties(desiredProperties); QByteArray blob; - EntityItemProperties::propertiesToBlob(_scriptEngine, sessionID, properties, blob, allProperties); + EntityItemProperties::propertiesToBlob(*_scriptEngine, sessionID, properties, blob, allProperties); data[id] = blob; } }); @@ -335,7 +337,7 @@ void ScriptableAvatar::setAvatarEntityData(const AvatarEntityMap& avatarEntityDa while (dataItr != avatarEntityData.end()) { EntityItemProperties properties; const QByteArray& blob = dataItr.value(); - if (!blob.isNull() && EntityItemProperties::blobToProperties(_scriptEngine, blob, properties)) { + if (!blob.isNull() && EntityItemProperties::blobToProperties(*_scriptEngine, blob, properties)) { newProperties[dataItr.key()] = properties; } ++dataItr; @@ -415,7 +417,7 @@ void ScriptableAvatar::updateAvatarEntity(const QUuid& entityID, const QByteArra EntityItemPointer entity; EntityItemProperties properties; - if (!EntityItemProperties::blobToProperties(_scriptEngine, entityData, properties)) { + if (!EntityItemProperties::blobToProperties(*_scriptEngine, entityData, properties)) { // entityData is corrupt return; } diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 1e6046ba7e7..3b08f763a3a 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -220,7 +220,7 @@ public slots: QHash _fstJointIndices; ///< 1-based, since zero is returned for missing keys QStringList _fstJointNames; ///< in order of depth-first traversal QUrl _skeletonFBXURL; - mutable QScriptEngine _scriptEngine; + mutable ScriptEnginePointer _scriptEngine; std::map _entities; /// Loads the joint indices, names from the FST file (if any) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 16931e8c266..b0278e9bdca 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -14,7 +14,9 @@ #include #include +#include #include +#include #include #include #include @@ -130,7 +132,7 @@ void EntityScriptServer::handleEntityScriptGetStatusPacket(QSharedPointerwritePrimitive(messageID); EntityScriptDetails details; - if (_entitiesScriptEngine->getEntityScriptDetails(entityID, details)) { + if (_entitiesScriptManager->getEntityScriptDetails(entityID, details)) { replyPacketList->writePrimitive(true); replyPacketList->writePrimitive(details.status); replyPacketList->writeString(details.errorInfo); @@ -175,7 +177,7 @@ void EntityScriptServer::handleSettings() { } void EntityScriptServer::updateEntityPPS() { - int numRunningScripts = _entitiesScriptEngine->getNumRunningEntityScripts(); + int numRunningScripts = _entitiesScriptManager->getNumRunningEntityScripts(); int pps; if (std::numeric_limits::max() / _entityPPSPerScript < numRunningScripts) { qWarning() << QString("Integer multiplication would overflow, clamping to maxint: %1 * %2").arg(numRunningScripts).arg(_entityPPSPerScript); @@ -236,7 +238,7 @@ void EntityScriptServer::pushLogs() { void EntityScriptServer::handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode) { - if (_entitiesScriptEngine && _entityViewer.getTree() && !_shuttingDown) { + if (_entitiesScriptManager && _entityViewer.getTree() && !_shuttingDown) { auto entityID = QUuid::fromRfc4122(receivedMessage->read(NUM_BYTES_RFC4122_UUID)); auto method = receivedMessage->readString(); @@ -250,13 +252,13 @@ void EntityScriptServer::handleEntityScriptCallMethodPacket(QSharedPointercallEntityScriptMethod(entityID, method, params, senderNode->getUUID()); + _entitiesScriptManager->callEntityScriptMethod(entityID, method, params, senderNode->getUUID()); } } void EntityScriptServer::run() { - DependencyManager::set(ScriptEngine::ENTITY_SERVER_SCRIPT); + DependencyManager::set(ScriptManager::ENTITY_SERVER_SCRIPT); DependencyManager::set(); DependencyManager::set(); @@ -446,52 +448,53 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) { void EntityScriptServer::resetEntitiesScriptEngine() { auto engineName = QString("about:Entities %1").arg(++_entitiesScriptEngineCount); - auto newEngine = scriptEngineFactory(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName); + auto newManager = scriptManagerFactory(ScriptManager::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName); + auto newEngine = newManager->engine(); auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor); - newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); + newEngine->globalObject()->setProperty("WebSocketServer", webSocketServerConstructorValue); newEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); newEngine->registerGlobalObject("AvatarList", DependencyManager::get().data()); // connect this script engines printedMessage signal to the global ScriptEngines these various messages auto scriptEngines = DependencyManager::get().data(); - connect(newEngine.data(), &ScriptEngine::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); - connect(newEngine.data(), &ScriptEngine::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); - connect(newEngine.data(), &ScriptEngine::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); - connect(newEngine.data(), &ScriptEngine::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); + connect(newManager.data(), &ScriptManager::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); + connect(newManager.data(), &ScriptManager::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); + connect(newManager.data(), &ScriptManager::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); + connect(newManager.data(), &ScriptManager::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); - connect(newEngine.data(), &ScriptEngine::update, this, [this] { + connect(newManager.data(), &ScriptManager::update, this, [this] { _entityViewer.queryOctree(); _entityViewer.getTree()->preUpdate(); _entityViewer.getTree()->update(); }); - scriptEngines->runScriptInitializers(newEngine); - newEngine->runInThread(); - auto newEngineSP = qSharedPointerCast(newEngine); + scriptEngines->runScriptInitializers(newManager); + newManager->runInThread(); + auto newEngineSP = qSharedPointerCast(newManager); // On the entity script server, these are the same DependencyManager::get()->setPersistentEntitiesScriptEngine(newEngineSP); DependencyManager::get()->setNonPersistentEntitiesScriptEngine(newEngineSP); - if (_entitiesScriptEngine) { - disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, + if (_entitiesScriptManager) { + disconnect(_entitiesScriptManager.data(), &ScriptManager::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS); } - _entitiesScriptEngine.swap(newEngine); - connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, + _entitiesScriptManager.swap(newManager); + connect(_entitiesScriptManager.data(), &ScriptManager::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS); } void EntityScriptServer::clear() { // unload and stop the engine - if (_entitiesScriptEngine) { + if (_entitiesScriptManager) { // do this here (instead of in deleter) to avoid marshalling unload signals back to this thread - _entitiesScriptEngine->unloadAllEntityScripts(); - _entitiesScriptEngine->stop(); - _entitiesScriptEngine->waitTillDoneRunning(); + _entitiesScriptManager->unloadAllEntityScripts(); + _entitiesScriptManager->stop(); + _entitiesScriptManager->waitTillDoneRunning(); } _entityViewer.clear(); @@ -503,8 +506,8 @@ void EntityScriptServer::clear() { } void EntityScriptServer::shutdownScriptEngine() { - if (_entitiesScriptEngine) { - _entitiesScriptEngine->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential + if (_entitiesScriptManager) { + _entitiesScriptManager->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential } _shuttingDown = true; @@ -513,7 +516,7 @@ void EntityScriptServer::shutdownScriptEngine() { auto scriptEngines = DependencyManager::get(); scriptEngines->shutdownScripting(); - _entitiesScriptEngine.clear(); + _entitiesScriptManager.clear(); auto entityScriptingInterface = DependencyManager::get(); // our entity tree is going to go away so tell that to the EntityScriptingInterface @@ -531,8 +534,8 @@ void EntityScriptServer::addingEntity(const EntityItemID& entityID) { } void EntityScriptServer::deletingEntity(const EntityItemID& entityID) { - if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) { - _entitiesScriptEngine->unloadEntityScript(entityID, true); + if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptManager) { + _entitiesScriptManager->unloadEntityScript(entityID, true); } } @@ -543,20 +546,20 @@ void EntityScriptServer::entityServerScriptChanging(const EntityItemID& entityID } void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool forceRedownload) { - if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) { + if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptManager) { EntityItemPointer entity = _entityViewer.getTree()->findEntityByEntityItemID(entityID); EntityScriptDetails details; - bool isRunning = _entitiesScriptEngine->getEntityScriptDetails(entityID, details); + bool isRunning = _entitiesScriptManager->getEntityScriptDetails(entityID, details); if (entity && (forceRedownload || !isRunning || details.scriptText != entity->getServerScripts())) { if (isRunning) { - _entitiesScriptEngine->unloadEntityScript(entityID, true); + _entitiesScriptManager->unloadEntityScript(entityID, true); } QString scriptUrl = entity->getServerScripts(); if (!scriptUrl.isEmpty()) { scriptUrl = DependencyManager::get()->normalizeURL(scriptUrl); - _entitiesScriptEngine->loadEntityScript(entityID, scriptUrl, forceRedownload); + _entitiesScriptManager->loadEntityScript(entityID, scriptUrl, forceRedownload); } } } @@ -573,9 +576,9 @@ void EntityScriptServer::sendStatsPacket() { QJsonObject scriptEngineStats; int numberRunningScripts = 0; - const auto scriptEngine = _entitiesScriptEngine; - if (scriptEngine) { - numberRunningScripts = scriptEngine->getNumRunningEntityScripts(); + const auto scriptManager = _entitiesScriptManager; + if (scriptManager) { + numberRunningScripts = scriptManager->getNumRunningEntityScripts(); } scriptEngineStats["number_running_scripts"] = numberRunningScripts; statsObject["script_engine_stats"] = scriptEngineStats; diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index b795339174e..a19578c1a35 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -17,12 +17,14 @@ #include #include +#include #include #include -#include #include #include +#include + #include "../entities/EntityTreeHeadlessViewer.h" class EntityScriptServer : public ThreadedAssignment { @@ -75,7 +77,7 @@ private slots: bool _shuttingDown { false }; static int _entitiesScriptEngineCount; - ScriptEnginePointer _entitiesScriptEngine; + ScriptManagerPointer _entitiesScriptManager; SimpleEntitySimulationPointer _entitySimulation; EntityEditPacketSender _entityEditSender; EntityTreeHeadlessViewer _entityViewer; diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index a3a85684b4d..6f123f23612 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -25,6 +25,7 @@ symlink_or_copy_directory_beside_target(${_SHOULD_SYMLINK_RESOURCES} "${CMAKE_CU # link the shared hifi libraries include_hifi_library_headers(gpu) include_hifi_library_headers(graphics) +include_hifi_library_headers(script-engine) link_hifi_libraries(embedded-webserver networking shared avatars octree) target_zlib() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index c307c631425..055da3c4278 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -98,7 +98,7 @@ endif () find_package( Qt5 COMPONENTS - Gui Widgets Multimedia Network Qml Quick Script Svg + Gui Widgets Multimedia Network Qml Quick Svg ${PLATFORM_QT_COMPONENTS} WebChannel WebSockets ) @@ -230,7 +230,7 @@ link_hifi_libraries( shared workload task octree ktx gpu gl procedural graphics graphics-scripting render pointers recording hfm model-serializers networking material-networking model-networking model-baker entities avatars - audio audio-client animation script-engine physics + audio audio-client animation physics render-utils entities-renderer avatars-renderer ui qml auto-updater midi controllers plugins image platform ui-plugins display-plugins input-plugins @@ -240,6 +240,7 @@ link_hifi_libraries( ${PLATFORM_PLUGIN_LIBRARIES} shaders ) +include_hifi_library_headers(script-engine) # include the binary directory of render-utils for shader includes target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils") @@ -304,7 +305,7 @@ endif () target_link_libraries( ${TARGET_NAME} Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::Widgets - Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg + Qt5::Qml Qt5::Quick Qt5::Svg Qt5::WebChannel ${PLATFORM_QT_LIBRARIES} ) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dad22f6b1ff..cab82621c69 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -130,6 +130,7 @@ #include #include #include +#include #include #include #include @@ -137,8 +138,11 @@ #include #include #include -#include #include +#include +#include +#include +#include #include #include #include @@ -165,6 +169,7 @@ #include #include #include "recording/ClipCache.h" +#include #include "AudioClient.h" #include "audio/AudioScope.h" @@ -863,7 +868,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { #endif DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(ScriptEngine::CLIENT_SCRIPT, defaultScriptsOverrideOption); + DependencyManager::set(ScriptManager::CLIENT_SCRIPT, defaultScriptsOverrideOption); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -1448,8 +1453,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo { auto scriptEngines = DependencyManager::get().data(); - scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine) { - registerScriptEngineWithApplicationServices(engine); + scriptEngines->registerScriptInitializer([this](ScriptManagerPointer manager) { + registerScriptEngineWithApplicationServices(manager); }); connect(scriptEngines, &ScriptEngines::scriptCountChanged, this, [this] { @@ -5874,7 +5879,7 @@ void Application::loadAvatarScripts(const QVector& urls) { if (index < 0) { auto scriptEnginePointer = scriptEngines->loadScript(url, false); if (scriptEnginePointer) { - scriptEnginePointer->setType(ScriptEngine::Type::AVATAR); + scriptEnginePointer->setType(ScriptManager::Type::AVATAR); } } } @@ -5885,7 +5890,7 @@ void Application::unloadAvatarScripts() { auto urls = scriptEngines->getRunningScripts(); for (auto url : urls) { auto scriptEngine = scriptEngines->getScriptEngine(url); - if (scriptEngine->getType() == ScriptEngine::Type::AVATAR) { + if (scriptEngine->getType() == ScriptManager::Type::AVATAR) { scriptEngines->stopScript(url, false); } } @@ -7475,9 +7480,10 @@ void Application::addingEntityWithCertificate(const QString& certificateID, cons ledger->updateLocation(certificateID, placeName); } -void Application::registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) { +void Application::registerScriptEngineWithApplicationServices(const ScriptManagerPointer& scriptManager) { - scriptEngine->setEmitScriptUpdatesFunction([this]() { + auto scriptEngine = scriptManager->engine(); + scriptManager->setEmitScriptUpdatesFunction([this]() { SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer); return !entityServerNode || isPhysicsEnabled(); }); @@ -7509,13 +7515,13 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface(); scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); - connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); + connect(scriptManager.data(), &ScriptManager::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); scriptEngine->registerGlobalObject("Overlays", &_overlays); - qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue, + scriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue, RayToOverlayIntersectionResultFromScriptValue); - bool clientScript = scriptEngine->isClientScript(); + bool clientScript = scriptManager->isClientScript(); #if !defined(DISABLE_QML) scriptEngine->registerGlobalObject("OffscreenFlags", getOffscreenUI()->getFlags()); @@ -7530,13 +7536,13 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine } #endif - qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - qScriptRegisterMetaType(scriptEngine.data(), + scriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); + scriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get().data()); - qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - qScriptRegisterMetaType(scriptEngine.data(), + scriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); + scriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); // FIXME remove these deprecated names for the tablet scripting interface @@ -7587,12 +7593,12 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine scriptEngine->registerGlobalObject("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED scriptEngine->registerGlobalObject("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED scriptEngine->registerGlobalObject("AccountServices", AccountServicesScriptingInterface::getInstance()); - qScriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); + scriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); scriptEngine->registerGlobalObject("AvatarManager", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LODManager", DependencyManager::get().data()); - qScriptRegisterMetaType(scriptEngine.data(), worldDetailQualityToScriptValue, worldDetailQualityFromScriptValue); + scriptRegisterMetaType(scriptEngine.data(), worldDetailQualityToScriptValue, worldDetailQualityFromScriptValue); scriptEngine->registerGlobalObject("Keyboard", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Performance", new PerformanceScriptingInterface()); @@ -7619,7 +7625,7 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { - scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine.data(), steamClient.get())); + scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptManager.data(), steamClient.get())); } auto scriptingInterface = DependencyManager::get(); scriptEngine->registerGlobalObject("Controller", scriptingInterface.data()); @@ -7646,11 +7652,11 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine // connect this script engines printedMessage signal to the global ScriptEngines these various messages auto scriptEngines = DependencyManager::get().data(); - connect(scriptEngine.data(), &ScriptEngine::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); - connect(scriptEngine.data(), &ScriptEngine::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); - connect(scriptEngine.data(), &ScriptEngine::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); - connect(scriptEngine.data(), &ScriptEngine::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); - connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow, scriptEngines, &ScriptEngines::onClearDebugWindow); + connect(scriptManager.data(), &ScriptManager::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); + connect(scriptManager.data(), &ScriptManager::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); + connect(scriptManager.data(), &ScriptManager::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); + connect(scriptManager.data(), &ScriptManager::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); + connect(scriptManager.data(), &ScriptManager::clearDebugWindow, scriptEngines, &ScriptEngines::onClearDebugWindow); } diff --git a/interface/src/Application.h b/interface/src/Application.h index e771d7ea388..679f3509bb2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -20,11 +20,13 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -39,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -88,6 +89,8 @@ class MainWindow; class AssetUpload; class CompositorHelper; class AudioInjector; +class ScriptEngine; +using ScriptEnginePointer = QSharedPointer; namespace controller { class StateController; @@ -243,7 +246,7 @@ class Application : public QApplication, NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } - virtual void registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) override; + virtual void registerScriptEngineWithApplicationServices(const ScriptManagerPointer& scriptManager) override; virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { copyDisplayViewFrustum(viewOut); } virtual QThread* getMainThread() override { return thread(); } diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 9aa1d91a0fd..ab1bd7e24a9 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -49,12 +49,12 @@ void addAvatarEntities(const QVariantList& avatarEntities) { EntitySimulationPointer entitySimulation = entityTree->getSimulation(); PhysicalEntitySimulationPointer physicalEntitySimulation = std::static_pointer_cast(entitySimulation); EntityEditPacketSender* entityPacketSender = physicalEntitySimulation->getPacketSender(); - QScriptEngine scriptEngine; + ScriptEnginePointer scriptEngine = newScriptEngine(); for (int index = 0; index < avatarEntities.count(); index++) { const QVariantMap& avatarEntityProperties = avatarEntities.at(index).toMap(); QVariant variantProperties = avatarEntityProperties["properties"]; QVariantMap asMap = variantProperties.toMap(); - QScriptValue scriptProperties = variantMapToScriptValue(asMap, scriptEngine); + ScriptValuePointer scriptProperties = variantMapToScriptValue(asMap, *scriptEngine); EntityItemProperties entityProperties; EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptProperties, entityProperties); @@ -298,7 +298,7 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; if (entityTree) { - QScriptEngine scriptEngine; + ScriptEnginePointer scriptEngine = newScriptEngine(); auto avatarEntities = myAvatar->getAvatarEntityDataNonDefault(); for (auto entityID : avatarEntities.keys()) { auto entity = entityTree->findEntityByID(entityID); @@ -318,8 +318,8 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { desiredProperties -= PROP_JOINT_TRANSLATIONS; EntityItemProperties entityProperties = entity->getProperties(desiredProperties); - QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties); - avatarEntityData["properties"] = scriptProperties.toVariant(); + ScriptValuePointer scriptProperties = EntityItemPropertiesToScriptValue(scriptEngine.get(), entityProperties); + avatarEntityData["properties"] = scriptProperties->toVariant(); wearableEntities.append(QVariant(avatarEntityData)); } } diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 1c6ef387f3a..d5da45341bc 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -426,13 +426,13 @@ WorldDetailQuality LODManager::getWorldDetailQuality() const { return qApp->isHMDMode() ? _hmdWorldDetailQuality : _desktopWorldDetailQuality; } -QScriptValue worldDetailQualityToScriptValue(QScriptEngine* engine, const WorldDetailQuality& worldDetailQuality) { - return worldDetailQuality; +ScriptValuePointer worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality) { + return engine->newValue(worldDetailQuality); } -void worldDetailQualityFromScriptValue(const QScriptValue& object, WorldDetailQuality& worldDetailQuality) { +void worldDetailQualityFromScriptValue(const ScriptValuePointer& object, WorldDetailQuality& worldDetailQuality) { worldDetailQuality = - static_cast(std::min(std::max(object.toInt32(), (int)WORLD_DETAIL_LOW), (int)WORLD_DETAIL_HIGH)); + static_cast(std::min(std::max(object->toInt32(), (int)WORLD_DETAIL_LOW), (int)WORLD_DETAIL_HIGH)); } void LODManager::setLODQualityLevel(float quality) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 35f80efcda9..e644379b01a 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -14,6 +14,7 @@ #define hifi_LODManager_h #include +#include #include #include @@ -23,6 +24,9 @@ #include #include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc *

The world detail quality rendered.

@@ -380,7 +384,7 @@ class LODManager : public QObject, public Dependency { glm::vec4 _pidOutputs{ 0.0f }; }; -QScriptValue worldDetailQualityToScriptValue(QScriptEngine* engine, const WorldDetailQuality& worldDetailQuality); -void worldDetailQualityFromScriptValue(const QScriptValue& object, WorldDetailQuality& worldDetailQuality); +ScriptValuePointer worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality); +void worldDetailQualityFromScriptValue(const ScriptValuePointer& object, WorldDetailQuality& worldDetailQuality); #endif // hifi_LODManager_h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3a320cc6287..a462e7fa96e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index b119f21f17b..7660fb34e41 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -13,7 +13,8 @@ #include -#include +#include +#include #include "AvatarLogging.h" @@ -735,8 +736,8 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) } RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& ray, - const QScriptValue& avatarIdsToInclude, - const QScriptValue& avatarIdsToDiscard, + const ScriptValuePointer& avatarIdsToInclude, + const ScriptValuePointer& avatarIdsToDiscard, bool pickAgainstMesh) { QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); @@ -980,10 +981,10 @@ float AvatarManager::getAvatarSortCoefficient(const QString& name) { } // HACK -void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptValue& value) { +void AvatarManager::setAvatarSortCoefficient(const QString& name, const ScriptValuePointer& value) { bool somethingChanged = false; - if (value.isNumber()) { - float numericalValue = (float)value.toNumber(); + if (value->isNumber()) { + float numericalValue = (float)value->toNumber(); if (name == "size") { AvatarData::_avatarSortCoefficientSize = numericalValue; somethingChanged = true; diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 30f68297b4c..fbaaad4ee60 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -33,8 +33,10 @@ #include "MyAvatar.h" #include "OtherAvatar.h" - +class ScriptEngine; +class ScriptValue; using SortedAvatar = std::pair>; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The AvatarManager API provides information about avatars within the current domain. The avatars available are @@ -95,7 +97,7 @@ class AvatarManager : public AvatarHashMap { */ /// Registers the script types associated with the avatar manager. - static void registerMetaTypes(QScriptEngine* engine); + static void registerMetaTypes(ScriptEngine* engine); virtual ~AvatarManager(); @@ -186,8 +188,8 @@ class AvatarManager : public AvatarHashMap { * } */ Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, - const QScriptValue& avatarIdsToInclude = QScriptValue(), - const QScriptValue& avatarIdsToDiscard = QScriptValue(), + const ScriptValuePointer& avatarIdsToInclude = ScriptValuePointer(), + const ScriptValuePointer& avatarIdsToDiscard = ScriptValuePointer(), bool pickAgainstMesh = true); /**jsdoc * @function AvatarManager.findRayIntersectionVector @@ -230,7 +232,7 @@ class AvatarManager : public AvatarHashMap { * @param {number} value - Value. * @deprecated This function is deprecated and will be removed. */ - Q_INVOKABLE void setAvatarSortCoefficient(const QString& name, const QScriptValue& value); + Q_INVOKABLE void setAvatarSortCoefficient(const QString& name, const ScriptValuePointer& value); /**jsdoc * Gets PAL (People Access List) data for one or more avatars. Using this method is faster than iterating over each avatar diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e8c91e79735..d308757f339 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include #include @@ -377,8 +379,7 @@ MyAvatar::MyAvatar(QThread* thread) : MyAvatar::~MyAvatar() { _lookAtTargetAvatar.reset(); - delete _scriptEngine; - _scriptEngine = nullptr; + _scriptEngine.reset(); if (_addAvatarEntitiesToTreeTimer.isActive()) { _addAvatarEntitiesToTreeTimer.stop(); } @@ -438,18 +439,18 @@ void MyAvatar::enableHandTouchForID(const QUuid& entityID) { } void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) { - QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); - engine->globalObject().setProperty("MyAvatar", value); + ScriptValuePointer value = engine->newQObject(this, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); + engine->globalObject()->setProperty("MyAvatar", value); - QScriptValue driveKeys = engine->newObject(); + ScriptValuePointer driveKeys = engine->newObject(); auto metaEnum = QMetaEnum::fromType(); for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { - driveKeys.setProperty(metaEnum.key(i), metaEnum.value(i)); + driveKeys->setProperty(metaEnum.key(i), metaEnum.value(i)); } - engine->globalObject().setProperty("DriveKeys", driveKeys); + engine->globalObject()->setProperty("DriveKeys", driveKeys); - qScriptRegisterMetaType(engine.data(), audioListenModeToScriptValue, audioListenModeFromScriptValue); - qScriptRegisterMetaType(engine.data(), driveKeysToScriptValue, driveKeysFromScriptValue); + scriptRegisterMetaType(engine.data(), audioListenModeToScriptValue, audioListenModeFromScriptValue); + scriptRegisterMetaType(engine.data(), driveKeysToScriptValue, driveKeysFromScriptValue); } void MyAvatar::setOrientationVar(const QVariant& newOrientationVar) { @@ -2061,7 +2062,7 @@ void MyAvatar::avatarEntityDataToJson(QJsonObject& root) const { void MyAvatar::loadData() { if (!_scriptEngine) { - _scriptEngine = new QScriptEngine(); + _scriptEngine = newScriptEngine(); } getHead()->setBasePitch(_headPitchSetting.get()); @@ -2669,9 +2670,9 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() { EntityItemProperties entityProperties = entity->getProperties(desiredProperties); { std::lock_guard guard(_scriptEngineLock); - QScriptValue scriptProperties; - scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine, entityProperties); - avatarEntityData["properties"] = scriptProperties.toVariant(); + ScriptValuePointer scriptProperties; + scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties); + avatarEntityData["properties"] = scriptProperties->toVariant(); } avatarEntitiesData.append(QVariant(avatarEntityData)); } @@ -5702,20 +5703,20 @@ void MyAvatar::setAudioListenerMode(AudioListenerMode audioListenerMode) { } } -QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode) { - return audioListenerMode; +ScriptValuePointer audioListenModeToScriptValue(ScriptEngine* engine, const AudioListenerMode& audioListenerMode) { + return engine->newValue(audioListenerMode); } -void audioListenModeFromScriptValue(const QScriptValue& object, AudioListenerMode& audioListenerMode) { - audioListenerMode = static_cast(object.toUInt16()); +void audioListenModeFromScriptValue(const ScriptValuePointer& object, AudioListenerMode& audioListenerMode) { + audioListenerMode = static_cast(object->toUInt16()); } -QScriptValue driveKeysToScriptValue(QScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys) { - return driveKeys; +ScriptValuePointer driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys) { + return engine->newValue(driveKeys); } -void driveKeysFromScriptValue(const QScriptValue& object, MyAvatar::DriveKeys& driveKeys) { - driveKeys = static_cast(object.toUInt16()); +void driveKeysFromScriptValue(const ScriptValuePointer& object, MyAvatar::DriveKeys& driveKeys) { + driveKeys = static_cast(object->toUInt16()); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index b4153400a79..a49dea24a9f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -39,6 +39,10 @@ class AvatarActionHold; class ModelItemID; class MyHead; class DetailedMotionState; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; +using ScriptEnginePointer = QSharedPointer; /**jsdoc *

Locomotion control types.

@@ -867,7 +871,7 @@ class MyAvatar : public Avatar { * MyAvatar.removeAnimationStateHandler(handler); * }, 100); */ - Q_INVOKABLE QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { return _skeletonModel->getRig().addAnimationStateHandler(handler, propertiesList); } + Q_INVOKABLE ScriptValuePointer addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList) { return _skeletonModel->getRig().addAnimationStateHandler(handler, propertiesList); } /**jsdoc * Removes an animation state handler function. @@ -875,7 +879,7 @@ class MyAvatar : public Avatar { * @param {number} handler - The ID of the animation state handler function to remove. */ // Removes a handler previously added by addAnimationStateHandler. - Q_INVOKABLE void removeAnimationStateHandler(QScriptValue handler) { _skeletonModel->getRig().removeAnimationStateHandler(handler); } + Q_INVOKABLE void removeAnimationStateHandler(ScriptValuePointer handler) { _skeletonModel->getRig().removeAnimationStateHandler(handler); } /**jsdoc @@ -3096,7 +3100,7 @@ private slots: // // keep a ScriptEngine around so we don't have to instantiate on the fly (these are very slow to create/delete) mutable std::mutex _scriptEngineLock; - QScriptEngine* _scriptEngine { nullptr }; + ScriptEnginePointer _scriptEngine { nullptr }; bool _needToSaveAvatarEntitySettings { false }; bool _reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS] { false, false }; @@ -3113,11 +3117,11 @@ private slots: QTimer _addAvatarEntitiesToTreeTimer; }; -QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode); -void audioListenModeFromScriptValue(const QScriptValue& object, AudioListenerMode& audioListenerMode); +ScriptValuePointer audioListenModeToScriptValue(ScriptEngine* engine, const AudioListenerMode& audioListenerMode); +void audioListenModeFromScriptValue(const ScriptValuePointer& object, AudioListenerMode& audioListenerMode); -QScriptValue driveKeysToScriptValue(QScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys); -void driveKeysFromScriptValue(const QScriptValue& object, MyAvatar::DriveKeys& driveKeys); +ScriptValuePointer driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys); +void driveKeysFromScriptValue(const ScriptValuePointer& object, MyAvatar::DriveKeys& driveKeys); bool isWearableEntity(const EntityItemPointer& entity); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 16fe65a989f..5aacd724594 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -11,14 +11,14 @@ #include "LaserPointerScriptingInterface.h" -#include "RegisteredMetaTypes.h" #include "PointerScriptingInterface.h" +#include -void LaserPointerScriptingInterface::setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems) const { +void LaserPointerScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void LaserPointerScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValue& includeItems) const { +void LaserPointerScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems) const { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 5745e29e695..48f4842bf83 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -12,10 +12,14 @@ #define hifi_LaserPointerScriptingInterface_h #include +#include #include "DependencyManager.h" #include +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + class LaserPointerScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -113,7 +117,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pointer. * @param {Uuid[]} ignoreItems - A list of IDs to ignore. */ - Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const; + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreEntities) const; /**jsdoc * Sets a list of entity and avatar IDs that a pointer should include during intersection, instead of intersecting with @@ -122,7 +126,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pointer. * @param {Uuid[]} includeItems - A list of IDs to include. */ - Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const; + Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValuePointer& includeEntities) const; /**jsdoc diff --git a/interface/src/raypick/PathPointer.cpp b/interface/src/raypick/PathPointer.cpp index 8a1675cfe18..b0223888aa4 100644 --- a/interface/src/raypick/PathPointer.cpp +++ b/interface/src/raypick/PathPointer.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "PickScriptingInterface.h" #include "RayPick.h" diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 1f940f761d6..e6eac7d3ba6 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -29,6 +29,8 @@ #include "EntityTransformNode.h" #include +#include +#include static const float WEB_TOUCH_Y_OFFSET = 0.105f; // how far forward (or back with a negative number) to slide stylus in hand static const glm::vec3 TIP_OFFSET = glm::vec3(0.0f, StylusPick::WEB_STYLUS_LENGTH - WEB_TOUCH_Y_OFFSET, 0.0f); @@ -425,11 +427,11 @@ void PickScriptingInterface::setPrecisionPicking(unsigned int uid, bool precisio DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } -void PickScriptingInterface::setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems) { +void PickScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems) { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void PickScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValue& includeItems) { +void PickScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems) { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } @@ -445,23 +447,23 @@ bool PickScriptingInterface::isMouse(unsigned int uid) { return DependencyManager::get()->isMouse(uid); } -QScriptValue pickTypesToScriptValue(QScriptEngine* engine, const PickQuery::PickType& pickType) { - return pickType; +ScriptValuePointer pickTypesToScriptValue(ScriptEngine* engine, const PickQuery::PickType& pickType) { + return engine->newValue(pickType); } -void pickTypesFromScriptValue(const QScriptValue& object, PickQuery::PickType& pickType) { - pickType = static_cast(object.toUInt16()); +void pickTypesFromScriptValue(const ScriptValuePointer& object, PickQuery::PickType& pickType) { + pickType = static_cast(object->toUInt16()); } -void PickScriptingInterface::registerMetaTypes(QScriptEngine* engine) { - QScriptValue pickTypes = engine->newObject(); +void PickScriptingInterface::registerMetaTypes(ScriptEngine* engine) { + ScriptValuePointer pickTypes = engine->newObject(); auto metaEnum = QMetaEnum::fromType(); for (int i = 0; i < PickQuery::PickType::NUM_PICK_TYPES; ++i) { - pickTypes.setProperty(metaEnum.key(i), metaEnum.value(i)); + pickTypes->setProperty(metaEnum.key(i), metaEnum.value(i)); } - engine->globalObject().setProperty("PickType", pickTypes); + engine->globalObject()->setProperty("PickType", pickTypes); - qScriptRegisterMetaType(engine, pickTypesToScriptValue, pickTypesFromScriptValue); + scriptRegisterMetaType(engine, pickTypesToScriptValue, pickTypesFromScriptValue); } unsigned int PickScriptingInterface::getPerFrameTimeBudget() const { diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 58ed3326ecc..da68f89de77 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -9,12 +9,17 @@ #define hifi_PickScriptingInterface_h #include +#include #include #include #include #include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + /**jsdoc * The Picks API lets you create and manage objects for repeatedly calculating intersections. * @@ -103,7 +108,7 @@ class PickScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public: - void registerMetaTypes(QScriptEngine* engine); + void registerMetaTypes(ScriptEngine* engine); /**jsdoc * Creates a new pick. Different {@link PickType}s use different properties, and within one PickType the properties you @@ -245,7 +250,7 @@ class PickScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pick. * @param {Uuid[]} ignoreItems - The list of IDs to ignore. */ - Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems); + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems); /**jsdoc * Sets a list of entity and avatar IDs that a pick should include during intersection, instead of intersecting with @@ -255,7 +260,7 @@ class PickScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pick. * @param {Uuid[]} includeItems - The list of IDs to include. */ - Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeItems); + Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems); /**jsdoc * Checks if a pick is associated with the left hand: a ray or parabola pick with joint property set to diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index a3aeb314e56..c6370ffb354 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "Application.h" #include "PickManager.h" #include "LaserPointer.h" @@ -23,11 +25,11 @@ static const glm::quat X_ROT_NEG_90{ 0.70710678f, -0.70710678f, 0.0f, 0.0f }; static const glm::vec3 DEFAULT_POSITION_OFFSET{0.0f, 0.0f, -StylusPick::WEB_STYLUS_LENGTH / 2.0f}; static const glm::vec3 DEFAULT_MODEL_DIMENSIONS{0.01f, 0.01f, StylusPick::WEB_STYLUS_LENGTH}; -void PointerScriptingInterface::setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems) const { +void PointerScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void PointerScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValue& includeItems) const { +void PointerScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems) const { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 555136e7a7c..e72b4710de8 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -9,12 +9,16 @@ #define hifi_PointerScriptingInterface_h #include +#include #include "DependencyManager.h" #include "RegisteredMetaTypes.h" #include #include +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + /**jsdoc * The Pointers API lets you create, manage, and visually represent objects for repeatedly calculating * intersections with avatars, entities, and overlays. Pointers can also be configured to generate events on entities and @@ -365,7 +369,7 @@ class PointerScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pointer. * @param {Uuid[]} ignoreItems - A list of IDs to ignore. */ - Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const; + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreEntities) const; /**jsdoc * Sets a list of entity and avatar IDs that a pointer should include during intersection, instead of intersecting with @@ -375,7 +379,7 @@ class PointerScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pointer. * @param {Uuid[]} includeItems - A list of IDs to include. */ - Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const; + Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValuePointer& includeEntities) const; /**jsdoc diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index a837121e6ad..1ddbb487665 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -15,6 +15,7 @@ #include "GLMHelpers.h" #include +#include unsigned int RayPickScriptingInterface::createRayPick(const QVariant& properties) { return DependencyManager::get()->createPick(PickQuery::PickType::Ray, properties); @@ -45,11 +46,11 @@ void RayPickScriptingInterface::setPrecisionPicking(unsigned int uid, bool preci DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } -void RayPickScriptingInterface::setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems) { +void RayPickScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems) { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void RayPickScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValue& includeItems) { +void RayPickScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems) { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index 204407e92d7..33ce979da60 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -12,12 +12,16 @@ #define hifi_RayPickScriptingInterface_h #include +#include #include "RegisteredMetaTypes.h" #include #include "PickScriptingInterface.h" +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + /**jsdoc * The RayPick API is a subset of the {@link Picks} API, as used for ray picks. * @@ -121,7 +125,7 @@ class RayPickScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the ray pick. * @param {Uuid[]} ignoreItems - The list of IDs to ignore. */ - Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities); + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreEntities); /**jsdoc * Sets a list of entity and avatar IDs that a ray pick should include during intersection, instead of intersecting with @@ -130,7 +134,7 @@ class RayPickScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the ray pick. * @param {Uuid[]} includeItems - The list of IDs to include. */ - Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities); + Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValuePointer& includeEntities); /**jsdoc diff --git a/interface/src/scripting/AccountServicesScriptingInterface.cpp b/interface/src/scripting/AccountServicesScriptingInterface.cpp index 5f8fb065ffa..8e48e3b5ca1 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.cpp +++ b/interface/src/scripting/AccountServicesScriptingInterface.cpp @@ -118,27 +118,27 @@ DownloadInfoResult::DownloadInfoResult() : * @property {number[]} downloading - The download percentage remaining of each asset currently downloading. * @property {number} pending - The number of assets pending download. */ -QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result) { - QScriptValue object = engine->newObject(); +ScriptValuePointer DownloadInfoResultToScriptValue(ScriptEngine* engine, const DownloadInfoResult& result) { + ScriptValuePointer object = engine->newObject(); - QScriptValue array = engine->newArray(result.downloading.count()); + ScriptValuePointer array = engine->newArray(result.downloading.count()); for (int i = 0; i < result.downloading.count(); i += 1) { - array.setProperty(i, result.downloading[i]); + array->setProperty(i, result.downloading[i]); } - object.setProperty("downloading", array); - object.setProperty("pending", result.pending); + object->setProperty("downloading", array); + object->setProperty("pending", result.pending); return object; } -void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result) { - QList downloading = object.property("downloading").toVariant().toList(); +void DownloadInfoResultFromScriptValue(const ScriptValuePointer& object, DownloadInfoResult& result) { + QList downloading = object->property("downloading")->toVariant().toList(); result.downloading.clear(); for (int i = 0; i < downloading.count(); i += 1) { result.downloading.append(downloading[i].toFloat()); } - result.pending = object.property("pending").toVariant().toFloat(); + result.pending = object->property("pending")->toVariant().toFloat(); } DownloadInfoResult AccountServicesScriptingInterface::getDownloadInfo() { diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index 7336d3e5cc9..3a31217120b 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -13,15 +13,17 @@ #define hifi_AccountServicesScriptingInterface_h #include -#include -#include -#include #include #include +#include #include #include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + class DownloadInfoResult { public: DownloadInfoResult(); @@ -31,8 +33,8 @@ class DownloadInfoResult { Q_DECLARE_METATYPE(DownloadInfoResult) -QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result); -void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result); +ScriptValuePointer DownloadInfoResultToScriptValue(ScriptEngine* engine, const DownloadInfoResult& result); +void DownloadInfoResultFromScriptValue(const ScriptValuePointer& object, DownloadInfoResult& result); class AccountServicesScriptingInterface : public QObject { Q_OBJECT diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 5b90474d233..d7a3eac9f88 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -11,7 +11,7 @@ #include "AssetMappingsScriptingInterface.h" -#include +#include #include #include diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index b27a72fbd0f..bc0676b1bca 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -15,14 +15,12 @@ #define hifi_AssetMappingsScriptingInterface_h #include -#include #include #include #include "DependencyManager.h" - class AssetMappingModel : public QStandardItemModel { Q_OBJECT Q_PROPERTY(bool autoRefreshEnabled READ isAutoRefreshEnabled WRITE setAutoRefreshEnabled) diff --git a/interface/src/scripting/DesktopScriptingInterface.h b/interface/src/scripting/DesktopScriptingInterface.h index e57d7a68052..0c8dc741994 100644 --- a/interface/src/scripting/DesktopScriptingInterface.h +++ b/interface/src/scripting/DesktopScriptingInterface.h @@ -13,7 +13,6 @@ #define hifi_DesktopScriptingInterface_h #include -#include #include diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index 79c0452a452..cca69548199 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -11,14 +11,15 @@ #include "HMDScriptingInterface.h" -#include - #include #include #include #include #include #include +#include +#include +#include #include #include "Application.h" @@ -151,23 +152,23 @@ bool HMDScriptingInterface::getAwayStateWhenFocusLostInVREnabled() { } -QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer HMDScriptingInterface::getHUDLookAtPosition2D(ScriptContext* context, ScriptEngine* engine) { glm::vec3 hudIntersection; auto instance = DependencyManager::get(); if (instance->getHUDLookAtPosition3D(hudIntersection)) { glm::vec2 overlayPos = qApp->getApplicationCompositor().overlayFromSphereSurface(hudIntersection); - return qScriptValueFromValue(engine, overlayPos); + return scriptValueFromValue(engine, overlayPos); } - return QScriptValue::NullValue; + return engine->nullValue(); } -QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer HMDScriptingInterface::getHUDLookAtPosition3D(ScriptContext* context, ScriptEngine* engine) { glm::vec3 result; auto instance = DependencyManager::get(); if (instance->getHUDLookAtPosition3D(result)) { - return qScriptValueFromValue(engine, result); + return scriptValueFromValue(engine, result); } - return QScriptValue::NullValue; + return engine->nullValue(); } bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 30a1353d814..73d6dfb5974 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -14,15 +14,17 @@ #include -#include -class QScriptContext; -class QScriptEngine; - #include #include #include #include +#include + +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The HMD API provides access to the HMD used in VR display mode. @@ -442,14 +444,14 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen * @function HMD.getHUDLookAtPosition2D * @returns {Vec2} The position on the HUD overlay that your HMD is looking at, in pixels. */ - static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer getHUDLookAtPosition2D(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Gets the position on the HUD overlay that your HMD is looking at, in world coordinates. * @function HMD.getHUDLookAtPosition3D * @returns {Vec3} The position on the HUD overlay the your HMD is looking at, in world coordinates. */ - static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer getHUDLookAtPosition3D(ScriptContext* context, ScriptEngine* engine); bool isMounted() const override; diff --git a/interface/src/scripting/PlatformInfoScriptingInterface.h b/interface/src/scripting/PlatformInfoScriptingInterface.h index 25cdc99577d..09c695ae0e8 100644 --- a/interface/src/scripting/PlatformInfoScriptingInterface.h +++ b/interface/src/scripting/PlatformInfoScriptingInterface.h @@ -12,8 +12,6 @@ #include #include -class QScriptValue; - /**jsdoc * The PlatformInfo API provides information about the hardware platform being used. * diff --git a/interface/src/scripting/SettingsScriptingInterface.cpp b/interface/src/scripting/SettingsScriptingInterface.cpp index 13eddddb1f5..9ad2ef187c9 100644 --- a/interface/src/scripting/SettingsScriptingInterface.cpp +++ b/interface/src/scripting/SettingsScriptingInterface.cpp @@ -47,7 +47,7 @@ void SettingsScriptingInterface::setValue(const QString& setting, const QVariant } } // Make a deep-copy of the string. - // Dangling pointers can occur with QStrings that are implicitly shared from a QScriptEngine. + // Dangling pointers can occur with QStrings that are implicitly shared from a ScriptEngine. QString deepCopy = QString::fromUtf16(setting.utf16()); Setting::Handle(deepCopy).set(value); emit valueChanged(setting, value); diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 53630b3eede..1b7ef709e07 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -153,9 +154,9 @@ void TestScriptingInterface::savePhysicsSimulationStats(QString originalPath) { qApp->saveNextPhysicsStats(path); } -void TestScriptingInterface::profileRange(const QString& name, QScriptValue fn) { +void TestScriptingInterface::profileRange(const QString& name, ScriptValuePointer fn) { PROFILE_RANGE(script, name); - fn.call(); + fn->call(); } void TestScriptingInterface::clearCaches() { diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index dffda3ece0a..d7c501d705f 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -12,8 +12,10 @@ #include #include +#include -class QScriptValue; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class TestScriptingInterface : public QObject { Q_OBJECT @@ -127,7 +129,7 @@ public slots: * @param {string} name - Name used to reference the function * @param {function} function - Function to profile */ - Q_INVOKABLE void profileRange(const QString& name, QScriptValue function); + Q_INVOKABLE void profileRange(const QString& name, ScriptValuePointer function); /**jsdoc * Clear all caches (menu command Reload Content) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index c34d1ac0066..2ba394b1f6f 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -76,8 +76,8 @@ WindowScriptingInterface::~WindowScriptingInterface() { _messageBoxes.clear(); } -QScriptValue WindowScriptingInterface::hasFocus() { - return qApp->hasFocus(); +ScriptValuePointer WindowScriptingInterface::hasFocus() { + return engine()->newValue(qApp->hasFocus()); } void WindowScriptingInterface::setFocus() { @@ -96,28 +96,29 @@ void WindowScriptingInterface::raise() { /// Display an alert box /// \param const QString& message message to display -/// \return QScriptValue::UndefinedValue +/// \return ScriptValuePointer::UndefinedValue void WindowScriptingInterface::alert(const QString& message) { OffscreenUi::asyncWarning("", message, QMessageBox::Ok, QMessageBox::Ok); } /// Display a confirmation box with the options 'Yes' and 'No' /// \param const QString& message message to display -/// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise -QScriptValue WindowScriptingInterface::confirm(const QString& message) { - return QScriptValue((QMessageBox::Yes == OffscreenUi::question("", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))); +/// \return ScriptValuePointer `true` if 'Yes' was clicked, `false` otherwise +ScriptValuePointer WindowScriptingInterface::confirm(const QString& message) { + return engine()->newValue((QMessageBox::Yes == OffscreenUi::question("", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))); } /// Display a prompt with a text box /// \param const QString& message message to display /// \param const QString& defaultText default text in the text box -/// \return QScriptValue string text value in text box if the dialog was accepted, `null` otherwise. -QScriptValue WindowScriptingInterface::prompt(const QString& message, const QString& defaultText) { +/// \return ScriptValuePointer string text value in text box if the dialog was accepted, `null` otherwise. +ScriptValuePointer WindowScriptingInterface::prompt(const QString& message, const QString& defaultText) { QString result = OffscreenUi::getText(nullptr, "", message, QLineEdit::Normal, defaultText); - if (QScriptValue(result).equals("")) { - return QScriptValue::NullValue; + auto sResult = engine()->newValue(result); + if (sResult->equals(engine()->newValue(""))) { + return engine()->nullValue(); } - return QScriptValue(result); + return sResult; } /// Display a prompt with a text box @@ -217,8 +218,8 @@ void WindowScriptingInterface::ensureReticleVisible() const { /// working directory. /// \param const QString& title title of the window /// \param const QString& directory directory to start the directory browser at -/// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue` -QScriptValue WindowScriptingInterface::browseDir(const QString& title, const QString& directory) { +/// \return ScriptValuePointer file path as a string if one was selected, otherwise `ScriptValuePointer::NullValue` +ScriptValuePointer WindowScriptingInterface::browseDir(const QString& title, const QString& directory) { ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { @@ -231,7 +232,7 @@ QScriptValue WindowScriptingInterface::browseDir(const QString& title, const QSt if (!result.isEmpty()) { setPreviousBrowseLocation(QFileInfo(result).absolutePath()); } - return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result); + return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result); } /// Display a "browse to directory" dialog. If `directory` is an invalid file or directory the browser will start at the current @@ -261,8 +262,8 @@ void WindowScriptingInterface::browseDirAsync(const QString& title, const QStrin /// \param const QString& title title of the window /// \param const QString& directory directory to start the file browser at /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` -/// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue` -QScriptValue WindowScriptingInterface::browse(const QString& title, const QString& directory, const QString& nameFilter) { +/// \return ScriptValuePointer file path as a string if one was selected, otherwise `ScriptValuePointer::NullValue` +ScriptValuePointer WindowScriptingInterface::browse(const QString& title, const QString& directory, const QString& nameFilter) { ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { @@ -275,7 +276,7 @@ QScriptValue WindowScriptingInterface::browse(const QString& title, const QStrin if (!result.isEmpty()) { setPreviousBrowseLocation(QFileInfo(result).absolutePath()); } - return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result); + return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result); } /// Display an open file dialog. If `directory` is an invalid file or directory the browser will start at the current @@ -308,8 +309,8 @@ void WindowScriptingInterface::browseAsync(const QString& title, const QString& /// \param const QString& title title of the window /// \param const QString& directory directory to start the file browser at /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` -/// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue` -QScriptValue WindowScriptingInterface::save(const QString& title, const QString& directory, const QString& nameFilter) { +/// \return ScriptValuePointer file path as a string if one was selected, otherwise `ScriptValuePointer::NullValue` +ScriptValuePointer WindowScriptingInterface::save(const QString& title, const QString& directory, const QString& nameFilter) { ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { @@ -322,7 +323,7 @@ QScriptValue WindowScriptingInterface::save(const QString& title, const QString& if (!result.isEmpty()) { setPreviousBrowseLocation(QFileInfo(result).absolutePath()); } - return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result); + return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result); } /// Display a save file dialog. If `directory` is an invalid file or directory the browser will start at the current @@ -355,8 +356,8 @@ void WindowScriptingInterface::saveAsync(const QString& title, const QString& di /// \param const QString& title title of the window /// \param const QString& directory directory to start the asset browser at /// \param const QString& nameFilter filter to filter asset names by - see `QFileDialog` -/// \return QScriptValue asset path as a string if one was selected, otherwise `QScriptValue::NullValue` -QScriptValue WindowScriptingInterface::browseAssets(const QString& title, const QString& directory, const QString& nameFilter) { +/// \return ScriptValuePointer asset path as a string if one was selected, otherwise `ScriptValuePointer::NullValue` +ScriptValuePointer WindowScriptingInterface::browseAssets(const QString& title, const QString& directory, const QString& nameFilter) { ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { @@ -372,7 +373,7 @@ QScriptValue WindowScriptingInterface::browseAssets(const QString& title, const if (!result.isEmpty()) { setPreviousBrowseAssetLocation(QFileInfo(result).absolutePath()); } - return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result); + return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result); } /// Display a select asset dialog that lets the user select an asset from the Asset Server. If `directory` is an invalid diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 86d0f400eab..aec9b4a7dc8 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -17,10 +17,15 @@ #include #include #include -#include #include +#include #include +#include + + +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The Window API provides various facilities not covered elsewhere, including: window dimensions, window focus, @@ -46,7 +51,7 @@ * @property {location} location - Provides facilities for working with your current metaverse location. */ -class WindowScriptingInterface : public QObject, public Dependency { +class WindowScriptingInterface : public QObject, protected Scriptable, public Dependency { Q_OBJECT Q_PROPERTY(int innerWidth READ getInnerWidth) Q_PROPERTY(int innerHeight READ getInnerHeight) @@ -69,7 +74,7 @@ public slots: * @function Window.hasFocus * @returns {boolean} true if the Interface window has focus, false if it doesn't. */ - QScriptValue hasFocus(); + ScriptValuePointer hasFocus(); /**jsdoc * Makes the Interface window have focus. On Windows, if Interface doesn't already have focus, the task bar icon flashes to @@ -104,7 +109,7 @@ public slots: * var answer = Window.confirm("Are you sure?"); * print(answer); // true or false */ - QScriptValue confirm(const QString& message = ""); + ScriptValuePointer confirm(const QString& message = ""); /**jsdoc * Prompts the user to enter some text. Displays a modal dialog with a message and a text box, plus "OK" and "Cancel" @@ -121,7 +126,7 @@ public slots: * print("User answer: " + answer); * } */ - QScriptValue prompt(const QString& message, const QString& defaultText); + ScriptValuePointer prompt(const QString& message, const QString& defaultText); /**jsdoc * Prompts the user to enter some text. Displays a non-modal dialog with a message and a text box, plus "OK" and "Cancel" @@ -151,7 +156,7 @@ public slots: * var directory = Window.browseDir("Select Directory", Paths.resources); * print("Directory: " + directory); */ - QScriptValue browseDir(const QString& title = "", const QString& directory = ""); + ScriptValuePointer browseDir(const QString& title = "", const QString& directory = ""); /**jsdoc * Prompts the user to choose a directory. Displays a non-modal dialog that navigates the directory tree. A @@ -183,7 +188,7 @@ public slots: * var filename = Window.browse("Select Image File", Paths.resources, "Images (*.png *.jpg *.svg)"); * print("File: " + filename); */ - QScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + ScriptValuePointer browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); /**jsdoc * Prompts the user to choose a file. Displays a non-modal dialog that navigates the directory tree. A @@ -219,7 +224,7 @@ public slots: * var filename = Window.save("Save to JSON file", Paths.resources, "*.json"); * print("File: " + filename); */ - QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + ScriptValuePointer save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); /**jsdoc * Prompts the user to specify the path and name of a file to save to. Displays a non-modal dialog that navigates the @@ -254,7 +259,7 @@ public slots: * var asset = Window.browseAssets("Select FBX File", "/", "*.fbx"); * print("FBX file: " + asset); */ - QScriptValue browseAssets(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + ScriptValuePointer browseAssets(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); /**jsdoc * Prompts the user to choose an Asset Server item. Displays a non-modal dialog that navigates the tree of assets on the diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index daf80acf000..898ee707721 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "OffscreenUi.h" #include "shared/QtHelpers.h" @@ -91,16 +93,16 @@ static void dockWidgetDeleter(DockWidget* dockWidget) { dockWidget->deleteLater(); } -void registerInteractiveWindowMetaType(QScriptEngine* engine) { - qScriptRegisterMetaType(engine, interactiveWindowPointerToScriptValue, interactiveWindowPointerFromScriptValue); +void registerInteractiveWindowMetaType(ScriptEngine* engine) { + scriptRegisterMetaType(engine, interactiveWindowPointerToScriptValue, interactiveWindowPointerFromScriptValue); } -QScriptValue interactiveWindowPointerToScriptValue(QScriptEngine* engine, const InteractiveWindowPointer& in) { - return engine->newQObject(in, QScriptEngine::ScriptOwnership); +ScriptValuePointer interactiveWindowPointerToScriptValue(ScriptEngine* engine, const InteractiveWindowPointer& in) { + return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void interactiveWindowPointerFromScriptValue(const QScriptValue& object, InteractiveWindowPointer& out) { - if (const auto interactiveWindow = qobject_cast(object.toQObject())) { +void interactiveWindowPointerFromScriptValue(const ScriptValuePointer& object, InteractiveWindowPointer& out) { + if (const auto interactiveWindow = qobject_cast(object->toQObject())) { out = interactiveWindow; } } diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h index 7c8897059f6..744bb5042bb 100644 --- a/interface/src/ui/InteractiveWindow.h +++ b/interface/src/ui/InteractiveWindow.h @@ -15,14 +15,18 @@ #define hifi_InteractiveWindow_h #include +#include #include -#include #include #include #include #include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + class QmlWindowProxy : public QmlWrapper { Q_OBJECT @@ -408,10 +412,10 @@ protected slots: typedef InteractiveWindow* InteractiveWindowPointer; -QScriptValue interactiveWindowPointerToScriptValue(QScriptEngine* engine, const InteractiveWindowPointer& in); -void interactiveWindowPointerFromScriptValue(const QScriptValue& object, InteractiveWindowPointer& out); +ScriptValuePointer interactiveWindowPointerToScriptValue(ScriptEngine* engine, const InteractiveWindowPointer& in); +void interactiveWindowPointerFromScriptValue(const ScriptValuePointer& object, InteractiveWindowPointer& out); -void registerInteractiveWindowMetaType(QScriptEngine* engine); +void registerInteractiveWindowMetaType(ScriptEngine* engine); Q_DECLARE_METATYPE(InteractiveWindowPointer) diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index ed4ee97780d..cdb819ecb7e 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -133,7 +135,7 @@ QStandardItemModel* JSConsole::getAutoCompleteModel(const QString& memberOf) { return model; } -JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) : +JSConsole::JSConsole(QWidget* parent, const ScriptManagerPointer& scriptManager) : QWidget(parent), _ui(new Ui::Console), _currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND), @@ -181,11 +183,11 @@ JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) : QObject::connect(_completer, static_cast(&QCompleter::highlighted), this, &JSConsole::highlightedCompletion); - setScriptEngine(scriptEngine); + setScriptManager(scriptManager); resizeTextInput(); - connect(&_executeWatcher, &QFutureWatcher::finished, this, &JSConsole::commandFinished); + connect(&_executeWatcher, &QFutureWatcher::finished, this, &JSConsole::commandFinished); } void JSConsole::insertCompletion(const QModelIndex& completion) { @@ -305,33 +307,33 @@ void JSConsole::highlightedCompletion(const QModelIndex& completion) { } JSConsole::~JSConsole() { - if (_scriptEngine) { - disconnect(_scriptEngine.data(), nullptr, this, nullptr); - _scriptEngine.reset(); + if (_scriptManager) { + disconnect(_scriptManager.data(), nullptr, this, nullptr); + _scriptManager.reset(); } delete _ui; } -void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) { - if (_scriptEngine == scriptEngine && scriptEngine != nullptr) { +void JSConsole::setScriptManager(const ScriptManagerPointer& scriptManager) { + if (_scriptManager == scriptManager && scriptManager != nullptr) { return; } - if (_scriptEngine != nullptr) { - disconnect(_scriptEngine.data(), nullptr, this, nullptr); - _scriptEngine.reset(); + if (scriptManager != nullptr) { + disconnect(_scriptManager.data(), nullptr, this, nullptr); + _scriptManager.reset(); } // if scriptEngine is nullptr then create one and keep track of it using _ownScriptEngine - if (scriptEngine.isNull()) { - _scriptEngine = DependencyManager::get()->loadScript(_consoleFileName, false); + if (scriptManager.isNull()) { + _scriptManager = DependencyManager::get()->loadScript(_consoleFileName, false); } else { - _scriptEngine = scriptEngine; + _scriptManager = scriptManager; } - connect(_scriptEngine.data(), &ScriptEngine::printedMessage, this, &JSConsole::handlePrint); - connect(_scriptEngine.data(), &ScriptEngine::infoMessage, this, &JSConsole::handleInfo); - connect(_scriptEngine.data(), &ScriptEngine::warningMessage, this, &JSConsole::handleWarning); - connect(_scriptEngine.data(), &ScriptEngine::errorMessage, this, &JSConsole::handleError); + connect(_scriptManager.data(), &ScriptManager::printedMessage, this, &JSConsole::handlePrint); + connect(_scriptManager.data(), &ScriptManager::infoMessage, this, &JSConsole::handleInfo); + connect(_scriptManager.data(), &ScriptManager::warningMessage, this, &JSConsole::handleWarning); + connect(_scriptManager.data(), &ScriptManager::errorMessage, this, &JSConsole::handleError); } void JSConsole::executeCommand(const QString& command) { @@ -347,14 +349,14 @@ void JSConsole::executeCommand(const QString& command) { appendMessage(">", "" + command.toHtmlEscaped() + ""); - QWeakPointer weakScriptEngine = _scriptEngine; + QWeakPointer weakScriptManager = _scriptManager; auto consoleFileName = _consoleFileName; - QFuture future = QtConcurrent::run([weakScriptEngine, consoleFileName, command]()->QScriptValue{ - QScriptValue result; - auto scriptEngine = weakScriptEngine.lock(); - if (scriptEngine) { - BLOCKING_INVOKE_METHOD(scriptEngine.data(), "evaluate", - Q_RETURN_ARG(QScriptValue, result), + QFuture future = QtConcurrent::run([weakScriptManager, consoleFileName, command]() -> ScriptValuePointer { + ScriptValuePointer result; + auto scriptManager = weakScriptManager.lock(); + if (scriptManager) { + BLOCKING_INVOKE_METHOD(scriptManager.data(), "evaluate", + Q_RETURN_ARG(ScriptValuePointer, result), Q_ARG(const QString&, command), Q_ARG(const QString&, consoleFileName)); } @@ -364,7 +366,7 @@ void JSConsole::executeCommand(const QString& command) { } void JSConsole::commandFinished() { - QScriptValue result = _executeWatcher.result(); + ScriptValuePointer result = _executeWatcher.result(); _ui->promptTextEdit->setDisabled(false); @@ -373,10 +375,10 @@ void JSConsole::commandFinished() { _ui->promptTextEdit->setFocus(); } - bool error = (_scriptEngine->hasUncaughtException() || result.isError()); + bool error = (_scriptManager->engine()->hasUncaughtException() || result->isError()); QString gutter = error ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND; QString resultColor = error ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE; - QString resultStr = "" + result.toString().toHtmlEscaped() + ""; + QString resultStr = "" + result->toString().toHtmlEscaped() + ""; appendMessage(gutter, resultStr); resetCurrentCommandHistory(); diff --git a/interface/src/ui/JSConsole.h b/interface/src/ui/JSConsole.h index eeb36018866..3b9ee9121af 100644 --- a/interface/src/ui/JSConsole.h +++ b/interface/src/ui/JSConsole.h @@ -19,7 +19,12 @@ #include #include "ui_console.h" -#include "ScriptEngine.h" + +class QStandardItemModel; +class ScriptManager; +class ScriptValue; +using ScriptManagerPointer = QSharedPointer; +using ScriptValuePointer = QSharedPointer; const QString CONSOLE_TITLE = "Scripting Console"; const float CONSOLE_WINDOW_OPACITY = 0.95f; @@ -29,10 +34,10 @@ const int CONSOLE_HEIGHT = 200; class JSConsole : public QWidget { Q_OBJECT public: - JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine = ScriptEnginePointer()); + JSConsole(QWidget* parent, const ScriptManagerPointer& scriptManager = ScriptManagerPointer()); ~JSConsole(); - void setScriptEngine(const ScriptEnginePointer& scriptEngine = ScriptEnginePointer()); + void setScriptManager(const ScriptManagerPointer& scriptManager = ScriptManagerPointer()); void clear(); public slots: @@ -67,13 +72,13 @@ private slots: QStandardItemModel* getAutoCompleteModel(const QString& memberOf = nullptr); - QFutureWatcher _executeWatcher; + QFutureWatcher _executeWatcher; Ui::Console* _ui; int _currentCommandInHistory; QString _savedHistoryFilename; QList _commandHistory; QString _rootCommand; - ScriptEnginePointer _scriptEngine; + ScriptManagerPointer _scriptManager; static const QString _consoleFileName; QJsonArray _apiDocs; QCompleter* _completer; diff --git a/interface/src/ui/TestingDialog.cpp b/interface/src/ui/TestingDialog.cpp index 5f0b20ca7e0..c357820cf35 100644 --- a/interface/src/ui/TestingDialog.cpp +++ b/interface/src/ui/TestingDialog.cpp @@ -13,6 +13,7 @@ #include "Application.h" #include "ScriptEngines.h" +#include TestingDialog::TestingDialog(QWidget* parent) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint), @@ -23,12 +24,12 @@ TestingDialog::TestingDialog(QWidget* parent) : _console->setFixedHeight(TESTING_CONSOLE_HEIGHT); - _engine = DependencyManager::get()->loadScript(qApp->applicationDirPath() + testRunnerRelativePath); - _console->setScriptEngine(_engine); - connect(_engine.data(), &ScriptEngine::finished, this, &TestingDialog::onTestingFinished); + _manager = DependencyManager::get()->loadScript(qApp->applicationDirPath() + testRunnerRelativePath); + _console->setScriptManager(_manager); + connect(_manager.data(), &ScriptManager::finished, this, &TestingDialog::onTestingFinished); } void TestingDialog::onTestingFinished(const QString& scriptPath) { - _engine.reset(); - _console->setScriptEngine(); + _manager.reset(); + _console->setScriptManager(); } diff --git a/interface/src/ui/TestingDialog.h b/interface/src/ui/TestingDialog.h index a7e909ca0e1..968188fbca4 100644 --- a/interface/src/ui/TestingDialog.h +++ b/interface/src/ui/TestingDialog.h @@ -13,9 +13,12 @@ #define hifi_TestingDialog_h #include -#include "ScriptEngine.h" +#include #include "JSConsole.h" +class ScriptManager; +using ScriptManagerPointer = QSharedPointer; + const QString windowLabel = "Client Script Tests"; const QString testRunnerRelativePath = "/scripts/developer/tests/unit_tests/testRunner.js"; const unsigned int TESTING_CONSOLE_HEIGHT = 400; @@ -29,7 +32,7 @@ class TestingDialog : public QDialog { private: std::unique_ptr _console; - ScriptEnginePointer _engine; + ScriptManagerPointer _manager; }; #endif diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index e9e310e68bc..cb44fdb2ff3 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -12,8 +12,6 @@ #include -#include - #include #include #include @@ -30,6 +28,8 @@ #include #include #include +#include +#include #include #include "VariantMapToScriptValue.h" @@ -42,7 +42,7 @@ Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays") std::unordered_map Overlays::_entityToOverlayTypes; std::unordered_map Overlays::_overlayToEntityTypes; -Overlays::Overlays() { +Overlays::Overlays() : _scriptEngine(newScriptEngine()) { ADD_TYPE_MAP(Box, cube); ADD_TYPE_MAP(Sphere, sphere); _overlayToEntityTypes["rectangle3d"] = "Shape"; @@ -632,16 +632,16 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove } } - QScriptEngine scriptEngine; - QScriptValue props = variantMapToScriptValue(overlayProps, scriptEngine); + ScriptEnginePointer scriptEngine = newScriptEngine(); + ScriptValuePointer props = variantMapToScriptValue(overlayProps, *scriptEngine); EntityItemProperties toReturn; EntityItemPropertiesFromScriptValueHonorReadOnly(props, toReturn); return toReturn; } QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemProperties& properties) { - QScriptEngine scriptEngine; - QVariantMap overlayProps = EntityItemPropertiesToScriptValue(&scriptEngine, properties).toVariant().toMap(); + ScriptEnginePointer scriptEngine = newScriptEngine(); + QVariantMap overlayProps = EntityItemPropertiesToScriptValue(scriptEngine.data(), properties)->toVariant().toMap(); QString type = overlayProps["type"].toString(); overlayProps["type"] = entityToOverlayType(type); @@ -740,7 +740,7 @@ QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemPropertie GROUP_ENTITY_TO_OVERLAY_PROP(ring, majorTickMarksColor, majorTickMarksColor); GROUP_ENTITY_TO_OVERLAY_PROP(ring, minorTickMarksColor, minorTickMarksColor); } else if (type == "PolyLine") { - QVector points = qVectorVec3FromScriptValue(scriptEngine.newVariant(overlayProps["linePoints"])); + QVector points = qVectorVec3FromScriptValue(scriptEngine->newVariant(overlayProps["linePoints"])); glm::vec3 position = vec3FromVariant(overlayProps["position"]); if (points.length() > 1) { overlayProps["p1"] = vec3toVariant(points[0] + position); @@ -755,7 +755,7 @@ QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemPropertie RENAME_PROP(p2, endPoint); RENAME_PROP(p2, end); - QVector widths = qVectorFloatFromScriptValue(scriptEngine.newVariant(overlayProps["strokeWidths"])); + QVector widths = qVectorFloatFromScriptValue(scriptEngine->newVariant(overlayProps["strokeWidths"])); if (widths.length() > 0) { overlayProps["lineWidth"] = widths[0]; } @@ -1041,8 +1041,8 @@ QVariantMap Overlays::getOverlaysProperties(const QVariant& propertiesById) { } RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, bool precisionPicking, - const QScriptValue& overlayIDsToInclude, - const QScriptValue& overlayIDsToDiscard, + const ScriptValuePointer& overlayIDsToInclude, + const ScriptValuePointer& overlayIDsToDiscard, bool visibleOnly, bool collidableOnly) { const QVector include = qVectorEntityItemIDFromScriptValue(overlayIDsToInclude); const QVector discard = qVectorEntityItemIDFromScriptValue(overlayIDsToDiscard); @@ -1110,38 +1110,38 @@ ParabolaToOverlayIntersectionResult Overlays::findParabolaIntersectionVector(con return overlayResult; } -QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) { - QScriptValue obj = engine->newObject(); - obj.setProperty("intersects", value.intersects); - QScriptValue overlayIDValue = quuidToScriptValue(engine, value.overlayID); - obj.setProperty("overlayID", overlayIDValue); - obj.setProperty("distance", value.distance); - obj.setProperty("face", boxFaceToString(value.face)); - - QScriptValue intersection = vec3ToScriptValue(engine, value.intersection); - obj.setProperty("intersection", intersection); - QScriptValue surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); - obj.setProperty("surfaceNormal", surfaceNormal); - obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); +ScriptValuePointer RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("intersects", value.intersects); + ScriptValuePointer overlayIDValue = quuidToScriptValue(engine, value.overlayID); + obj->setProperty("overlayID", overlayIDValue); + obj->setProperty("distance", value.distance); + obj->setProperty("face", boxFaceToString(value.face)); + + ScriptValuePointer intersection = vec3ToScriptValue(engine, value.intersection); + obj->setProperty("intersection", intersection); + ScriptValuePointer surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); + obj->setProperty("surfaceNormal", surfaceNormal); + obj->setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); return obj; } -void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, RayToOverlayIntersectionResult& value) { - value.intersects = object.property("intersects").toVariant().toBool(); - QScriptValue overlayIDValue = object.property("overlayID"); +void RayToOverlayIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToOverlayIntersectionResult& value) { + value.intersects = object->property("intersects")->toVariant().toBool(); + ScriptValuePointer overlayIDValue = object->property("overlayID"); quuidFromScriptValue(overlayIDValue, value.overlayID); - value.distance = object.property("distance").toVariant().toFloat(); - value.face = boxFaceFromString(object.property("face").toVariant().toString()); + value.distance = object->property("distance")->toVariant().toFloat(); + value.face = boxFaceFromString(object->property("face")->toVariant().toString()); - QScriptValue intersection = object.property("intersection"); - if (intersection.isValid()) { + ScriptValuePointer intersection = object->property("intersection"); + if (intersection->isValid()) { vec3FromScriptValue(intersection, value.intersection); } - QScriptValue surfaceNormal = object.property("surfaceNormal"); - if (surfaceNormal.isValid()) { + ScriptValuePointer surfaceNormal = object->property("surfaceNormal"); + if (surfaceNormal->isValid()) { vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } - value.extraInfo = object.property("extraInfo").toVariant().toMap(); + value.extraInfo = object->property("extraInfo")->toVariant().toMap(); } bool Overlays::isLoaded(const QUuid& id) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 6e59cbc00e9..51ea5dc9e7a 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -20,15 +20,18 @@ #include #include -#include #include +#include #include "Overlay.h" #include class PickRay; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection}. @@ -52,8 +55,8 @@ class RayToOverlayIntersectionResult { QVariantMap extraInfo; }; Q_DECLARE_METATYPE(RayToOverlayIntersectionResult); -QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value); -void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, RayToOverlayIntersectionResult& value); +ScriptValuePointer RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value); +void RayToOverlayIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToOverlayIntersectionResult& value); class ParabolaToOverlayIntersectionResult { public: @@ -120,7 +123,7 @@ class Overlays : public QObject { void cleanupAllOverlays(); - mutable QScriptEngine _scriptEngine; + mutable ScriptEnginePointer _scriptEngine; public slots: /**jsdoc @@ -411,8 +414,8 @@ public slots: */ RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false, - const QScriptValue& include = QScriptValue(), - const QScriptValue& discard = QScriptValue(), + const ScriptValuePointer& include = ScriptValuePointer(), + const ScriptValuePointer& discard = ScriptValuePointer(), bool visibleOnly = false, bool collidableOnly = false); diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index d962d9e2224..fe8a24b3cc7 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -1,9 +1,11 @@ set(TARGET_NAME animation) -setup_hifi_library(Network Script) -link_hifi_libraries(shared graphics model-serializers) -include_hifi_library_headers(networking) +setup_hifi_library(Network) +link_hifi_libraries(shared graphics model-serializers script-engine) +include_hifi_library_headers(animation) +include_hifi_library_headers(entities) include_hifi_library_headers(gpu) include_hifi_library_headers(hfm) include_hifi_library_headers(image) +include_hifi_library_headers(networking) target_nsight() diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index 1519aa8109e..9b596b2356b 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -11,39 +11,39 @@ #include "AnimVariant.h" // which has AnimVariant/AnimVariantMap -#include -#include +#include #include -#include +#include +#include const AnimVariant AnimVariant::False = AnimVariant(); -QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine, const QStringList& names, bool useNames) const { +ScriptValuePointer AnimVariantMap::animVariantMapToScriptValue(ScriptEngine* engine, const QStringList& names, bool useNames) const { if (QThread::currentThread() != engine->thread()) { qCWarning(animation) << "Cannot create Javacript object from non-script thread" << QThread::currentThread(); Q_ASSERT(false); - return QScriptValue(); + return ScriptValuePointer(); } - QScriptValue target = engine->newObject(); + ScriptValuePointer target = engine->newObject(); auto setOne = [&] (const QString& name, const AnimVariant& value) { switch (value.getType()) { case AnimVariant::Type::Bool: - target.setProperty(name, value.getBool()); + target->setProperty(name, value.getBool()); break; case AnimVariant::Type::Int: - target.setProperty(name, value.getInt()); + target->setProperty(name, value.getInt()); break; case AnimVariant::Type::Float: - target.setProperty(name, value.getFloat()); + target->setProperty(name, value.getFloat()); break; case AnimVariant::Type::String: - target.setProperty(name, value.getString()); + target->setProperty(name, value.getString()); break; case AnimVariant::Type::Vec3: - target.setProperty(name, vec3ToScriptValue(engine, value.getVec3())); + target->setProperty(name, vec3ToScriptValue(engine, value.getVec3())); break; case AnimVariant::Type::Quat: - target.setProperty(name, quatToScriptValue(engine, value.getQuat())); + target->setProperty(name, quatToScriptValue(engine, value.getQuat())); break; default: // Unknown type @@ -56,7 +56,7 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine, if (search != _map.end()) { setOne(name, search->second); } else if (_triggers.count(name) == 1) { - target.setProperty(name, true); + target->setProperty(name, true); } // scripts are allowed to request names that do not exist } @@ -74,8 +74,8 @@ void AnimVariantMap::copyVariantsFrom(const AnimVariantMap& other) { } } -void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) { - if (QThread::currentThread() != source.engine()->thread()) { +void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& source) { + if (QThread::currentThread() != source->engine()->thread()) { qCWarning(animation) << "Cannot examine Javacript object from non-script thread" << QThread::currentThread(); Q_ASSERT(false); return; @@ -84,43 +84,43 @@ void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) { // Whenever we identify a new outbound type in animVariantMapToScriptValue above, or a new inbound type in the code that follows here, // we would enter it into the dictionary. Then switch on that type here, with the code that follow being executed only if // the type is not known. One problem with that is that there is no checking that two different script use the same name differently. - QScriptValueIterator property(source); - // Note: QScriptValueIterator iterates only over source's own properties. It does not follow the prototype chain. - while (property.hasNext()) { - property.next(); - QScriptValue value = property.value(); - if (value.isBool()) { - set(property.name(), value.toBool()); - } else if (value.isString()) { - set(property.name(), value.toString()); - } else if (value.isNumber()) { - int asInteger = value.toInt32(); - float asFloat = value.toNumber(); + ScriptValueIteratorPointer property(source->newIterator()); + // Note: ScriptValueIterator iterates only over source's own properties. It does not follow the prototype chain. + while (property->hasNext()) { + property->next(); + ScriptValuePointer value = property->value(); + if (value->isBool()) { + set(property->name(), value->toBool()); + } else if (value->isString()) { + set(property->name(), value->toString()); + } else if (value->isNumber()) { + int asInteger = value->toInt32(); + float asFloat = value->toNumber(); if (asInteger == asFloat) { - set(property.name(), asInteger); + set(property->name(), asInteger); } else { - set(property.name(), asFloat); + set(property->name(), asFloat); } } else { // Try to get x,y,z and possibly w - if (value.isObject()) { - QScriptValue x = value.property("x"); - if (x.isNumber()) { - QScriptValue y = value.property("y"); - if (y.isNumber()) { - QScriptValue z = value.property("z"); - if (z.isNumber()) { - QScriptValue w = value.property("w"); - if (w.isNumber()) { - set(property.name(), glm::quat(w.toNumber(), x.toNumber(), y.toNumber(), z.toNumber())); + if (value->isObject()) { + ScriptValuePointer x = value->property("x"); + if (x->isNumber()) { + ScriptValuePointer y = value->property("y"); + if (y->isNumber()) { + ScriptValuePointer z = value->property("z"); + if (z->isNumber()) { + ScriptValuePointer w = value->property("w"); + if (w->isNumber()) { + set(property->name(), glm::quat(w->toNumber(), x->toNumber(), y->toNumber(), z->toNumber())); } else { - set(property.name(), glm::vec3(x.toNumber(), y.toNumber(), z.toNumber())); + set(property->name(), glm::vec3(x->toNumber(), y->toNumber(), z->toNumber())); } continue; // we got either a vector or quaternion object, so don't fall through to warning } } } } - qCWarning(animation) << "Ignoring unrecognized data" << value.toString() << "for animation property" << property.name(); + qCWarning(animation) << "Ignoring unrecognized data" << value->toString() << "for animation property" << property->name(); Q_ASSERT(false); } } diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index d9e75d5844f..15a0b0d48d7 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -17,10 +17,14 @@ #include #include #include -#include #include #include #include "AnimationLogging.h" +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class AnimVariant { public: @@ -229,9 +233,9 @@ class AnimVariantMap { } // Answer a Plain Old Javascript Object (for the given engine) all of our values set as properties. - QScriptValue animVariantMapToScriptValue(QScriptEngine* engine, const QStringList& names, bool useNames) const; + ScriptValuePointer animVariantMapToScriptValue(ScriptEngine* engine, const QStringList& names, bool useNames) const; // Side-effect us with the value of object's own properties. (No inherited properties.) - void animVariantMapFromScriptValue(const QScriptValue& object); + void animVariantMapFromScriptValue(const ScriptValuePointer& object); void copyVariantsFrom(const AnimVariantMap& other); // For stat debugging. @@ -274,7 +278,7 @@ class AnimVariantMap { glm::quat _rigToGeometryRot; }; -typedef std::function AnimVariantResultHandler; +typedef std::function AnimVariantResultHandler; Q_DECLARE_METATYPE(AnimVariantResultHandler); Q_DECLARE_METATYPE(AnimVariantMap) diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index e8bfa75ecb6..a1ba75879d7 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -13,8 +13,6 @@ #define hifi_AnimationCache_h #include -#include -#include #include #include diff --git a/libraries/animation/src/AnimationObject.cpp b/libraries/animation/src/AnimationObject.cpp index 831f310beec..20ecead184b 100644 --- a/libraries/animation/src/AnimationObject.cpp +++ b/libraries/animation/src/AnimationObject.cpp @@ -11,27 +11,29 @@ #include "AnimationObject.h" -#include +#include +#include +#include #include "AnimationCache.h" QStringList AnimationObject::getJointNames() const { - return qscriptvalue_cast(thisObject())->getJointNames(); + return scriptvalue_cast(thisObject())->getJointNames(); } QVector AnimationObject::getFrames() const { - return qscriptvalue_cast(thisObject())->getFrames(); + return scriptvalue_cast(thisObject())->getFrames(); } QVector AnimationFrameObject::getRotations() const { - return qscriptvalue_cast(thisObject()).rotations; + return scriptvalue_cast(thisObject()).rotations; } -void registerAnimationTypes(QScriptEngine* engine) { - qScriptRegisterSequenceMetaType >(engine); +void registerAnimationTypes(ScriptEngine* engine) { + scriptRegisterSequenceMetaType >(engine); engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject( - new AnimationFrameObject(), QScriptEngine::ScriptOwnership)); + new AnimationFrameObject(), ScriptEngine::ScriptOwnership)); engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject( - new AnimationObject(), QScriptEngine::ScriptOwnership)); + new AnimationObject(), ScriptEngine::ScriptOwnership)); } diff --git a/libraries/animation/src/AnimationObject.h b/libraries/animation/src/AnimationObject.h index 9df58a20afb..5e09ce1e0bb 100644 --- a/libraries/animation/src/AnimationObject.h +++ b/libraries/animation/src/AnimationObject.h @@ -13,11 +13,11 @@ #define hifi_AnimationObject_h #include -#include #include +#include "Scriptable.h" -class QScriptEngine; +class ScriptEngine; /**jsdoc * Information about an animation resource, created by {@link AnimationCache.getAnimation}. @@ -35,7 +35,7 @@ class QScriptEngine; * @property {AnimationFrameObject[]} frames - The frames in the animation. Read-only. */ /// Scriptable wrapper for animation pointers. -class AnimationObject : public QObject, protected QScriptable { +class AnimationObject : public QObject, protected Scriptable { Q_OBJECT Q_PROPERTY(QStringList jointNames READ getJointNames) Q_PROPERTY(QVector frames READ getFrames) @@ -72,7 +72,7 @@ class AnimationObject : public QObject, protected QScriptable { * @property {Quat[]} rotations - Joint rotations. Read-only. */ /// Scriptable wrapper for animation frames. -class AnimationFrameObject : public QObject, protected QScriptable { +class AnimationFrameObject : public QObject, protected Scriptable { Q_OBJECT Q_PROPERTY(QVector rotations READ getRotations) @@ -86,6 +86,6 @@ class AnimationFrameObject : public QObject, protected QScriptable { Q_INVOKABLE QVector getRotations() const; }; -void registerAnimationTypes(QScriptEngine* engine); +void registerAnimationTypes(ScriptEngine* engine); #endif // hifi_AnimationObject_h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index e0589fdba98..ae5f0c6253a 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -21,7 +20,10 @@ #include #include #include +#include +#include #include +#include #include #include "AnimationLogging.h" @@ -1584,10 +1586,10 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos } // Allow script to add/remove handlers and report results, from within their thread. -QScriptValue Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { // called in script thread +ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList) { // called in script thread // validate argument types - if (handler.isFunction() && (isListOfStrings(propertiesList) || propertiesList.isUndefined() || propertiesList.isNull())) { + if (handler->isFunction() && (isListOfStrings(propertiesList) || propertiesList->isUndefined() || propertiesList->isNull())) { QMutexLocker locker(&_stateMutex); // Find a safe id, even if there are lots of many scripts add and remove handlers repeatedly. while (!_nextStateHandlerId || _stateHandlers.contains(_nextStateHandlerId)) { // 0 is unused, and don't reuse existing after wrap. @@ -1595,28 +1597,28 @@ QScriptValue Rig::addAnimationStateHandler(QScriptValue handler, QScriptValue pr } StateHandler& data = _stateHandlers[_nextStateHandlerId]; data.function = handler; - data.useNames = propertiesList.isArray(); + data.useNames = propertiesList->isArray(); if (data.useNames) { - data.propertyNames = propertiesList.toVariant().toStringList(); + data.propertyNames = propertiesList->toVariant().toStringList(); } - return QScriptValue(_nextStateHandlerId); // suitable for giving to removeAnimationStateHandler + return handler->engine()->newValue(_nextStateHandlerId); // suitable for giving to removeAnimationStateHandler } else { qCWarning(animation) << "Rig::addAnimationStateHandler invalid arguments, expected (function, string[])"; - return QScriptValue(QScriptValue::UndefinedValue); + return handler ? handler->engine()->undefinedValue() : ScriptValuePointer(); } } -void Rig::removeAnimationStateHandler(QScriptValue identifier) { // called in script thread +void Rig::removeAnimationStateHandler(ScriptValuePointer identifier) { // called in script thread // validate arguments - if (identifier.isNumber()) { + if (identifier->isNumber()) { QMutexLocker locker(&_stateMutex); - _stateHandlers.remove(identifier.toInt32()); // silently continues if handler not present. 0 is unused + _stateHandlers.remove(identifier->toInt32()); // silently continues if handler not present. 0 is unused } else { qCWarning(animation) << "Rig::removeAnimationStateHandler invalid argument, expected a number"; } } -void Rig::animationStateHandlerResult(int identifier, QScriptValue result) { // called synchronously from script +void Rig::animationStateHandlerResult(int identifier, ScriptValuePointer result) { // called synchronously from script QMutexLocker locker(&_stateMutex); auto found = _stateHandlers.find(identifier); if (found == _stateHandlers.end()) { @@ -1635,9 +1637,9 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh // call out: int identifier = data.key(); StateHandler& value = data.value(); - QScriptValue& function = value.function; + ScriptValuePointer& function = value.function; int rigId = _rigId; - auto handleResult = [rigId, identifier](QScriptValue result) { // called in script thread to get the result back to us. + auto handleResult = [rigId, identifier](ScriptValuePointer result) { // called in script thread to get the result back to us. // Hold the rigRegistryMutex to ensure thread-safe access to the rigRegistry, but // also to prevent the rig from being deleted while this lambda is being executed. std::lock_guard guard(rigRegistryMutex); @@ -1652,8 +1654,8 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh }; // invokeMethod makes a copy of the args, and copies of AnimVariantMap do copy the underlying map, so this will correctly capture // the state of _animVars and allow continued changes to _animVars in this thread without conflict. - QMetaObject::invokeMethod(function.engine(), "callAnimationStateHandler", Qt::QueuedConnection, - Q_ARG(QScriptValue, function), + QMetaObject::invokeMethod(function->engine()->manager(), "callAnimationStateHandler", Qt::QueuedConnection, + Q_ARG(ScriptValuePointer, function), Q_ARG(AnimVariantMap, _animVars), Q_ARG(QStringList, value.propertyNames), Q_ARG(bool, value.useNames), diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 7ae48a90ee9..f2f672df35d 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -16,10 +16,10 @@ #include #include -#include #include #include #include +#include #include "AnimNode.h" #include "AnimNodeLoader.h" @@ -30,6 +30,8 @@ class Rig; class AnimInverseKinematics; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; // Rig instances are reentrant. // However only specific methods thread-safe. Noted below. @@ -40,7 +42,7 @@ class Rig : public QObject { struct StateHandler { AnimVariantMap results; QStringList propertyNames; - QScriptValue function; + ScriptValuePointer function; bool useNames; }; @@ -205,9 +207,9 @@ class Rig : public QObject { AnimNode::ConstPointer getAnimNode() const { return _animNode; } AnimNode::ConstPointer findAnimNodeByName(const QString& name) const; AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; } - QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList); - void removeAnimationStateHandler(QScriptValue handler); - void animationStateHandlerResult(int identifier, QScriptValue result); + ScriptValuePointer addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList); + void removeAnimationStateHandler(ScriptValuePointer handler); + void animationStateHandlerResult(int identifier, ScriptValuePointer result); // rig space bool getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const; diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index a8a398c14ff..7260e21259d 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -5,4 +5,4 @@ if (ANDROID) add_definitions("-D__STDC_CONSTANT_MACROS") endif () -link_hifi_libraries(networking shared plugins) +link_hifi_libraries(networking shared plugins script-engine) diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 873ce7df877..7451912ffef 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -10,6 +10,10 @@ #include "AudioEffectOptions.h" +#include +#include +#include + static const QString BANDWIDTH_HANDLE = "bandwidth"; static const QString PRE_DELAY_HANDLE = "preDelay"; static const QString LATE_DELAY_HANDLE = "lateDelay"; @@ -54,8 +58,8 @@ static const float LATE_MIX_LEFT_DEFAULT = 90.0f; static const float LATE_MIX_RIGHT_DEFAULT = 90.0f; static const float WET_DRY_MIX_DEFAULT = 50.0f; -static void setOption(QScriptValue arguments, const QString name, float defaultValue, float& variable) { - variable = arguments.property(name).isNumber() ? (float)arguments.property(name).toNumber() : defaultValue; +static void setOption(ScriptValuePointer arguments, const QString name, float defaultValue, float& variable) { + variable = arguments->property(name)->isNumber() ? (float)arguments->property(name)->toNumber() : defaultValue; } /**jsdoc @@ -83,7 +87,7 @@ static void setOption(QScriptValue arguments, const QString name, float defaultV * @property {number} lateMixRight=90 - The apparent distance of the source (percent) in the reverb tail. * @property {number} wetDryMix=50 - Adjusts the wet/dry ratio, from completely dry (0%) to completely wet (100%). */ -AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) { +AudioEffectOptions::AudioEffectOptions(ScriptValuePointer arguments) { setOption(arguments, BANDWIDTH_HANDLE, BANDWIDTH_DEFAULT, _bandwidth); setOption(arguments, PRE_DELAY_HANDLE, PRE_DELAY_DEFAULT, _preDelay); setOption(arguments, LATE_DELAY_HANDLE, LATE_DELAY_DEFAULT, _lateDelay); @@ -137,6 +141,6 @@ AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &othe return *this; } -QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer AudioEffectOptions::constructor(ScriptContext* context, ScriptEngine* engine) { return engine->newQObject(new AudioEffectOptions(context->argument(0))); } diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index 48fe44feb53..45026eb0c17 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -12,8 +12,12 @@ #define hifi_AudioEffectOptions_h #include -#include -#include +#include + +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * Audio effect options used by the {@link Audio} API. @@ -78,11 +82,11 @@ class AudioEffectOptions : public QObject { Q_PROPERTY(float wetDryMix READ getWetDryMix WRITE setWetDryMix) public: - AudioEffectOptions(QScriptValue arguments = QScriptValue()); + AudioEffectOptions(ScriptValuePointer arguments = ScriptValuePointer()); AudioEffectOptions(const AudioEffectOptions &other); AudioEffectOptions& operator=(const AudioEffectOptions &other); - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine); float getBandwidth() const { return _bandwidth; } void setBandwidth(float bandwidth) { _bandwidth = bandwidth; } diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 99a2886a77c..4c287e203bc 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -11,9 +11,9 @@ #include "AudioInjectorOptions.h" -#include - -#include +#include +#include +#include #include "AudioLogging.h" @@ -32,18 +32,18 @@ AudioInjectorOptions::AudioInjectorOptions() : { } -QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions) { - QScriptValue obj = engine->newObject(); +ScriptValuePointer injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInjectorOptions& injectorOptions) { + ScriptValuePointer obj = engine->newObject(); if (injectorOptions.positionSet) { - obj.setProperty("position", vec3ToScriptValue(engine, injectorOptions.position)); + obj->setProperty("position", vec3ToScriptValue(engine, injectorOptions.position)); } - obj.setProperty("volume", injectorOptions.volume); - obj.setProperty("loop", injectorOptions.loop); - obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); - obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra); - obj.setProperty("localOnly", injectorOptions.localOnly); - obj.setProperty("secondOffset", injectorOptions.secondOffset); - obj.setProperty("pitch", injectorOptions.pitch); + obj->setProperty("volume", injectorOptions.volume); + obj->setProperty("loop", injectorOptions.loop); + obj->setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); + obj->setProperty("ignorePenumbra", injectorOptions.ignorePenumbra); + obj->setProperty("localOnly", injectorOptions.localOnly); + obj->setProperty("secondOffset", injectorOptions.secondOffset); + obj->setProperty("pitch", injectorOptions.pitch); return obj; } @@ -66,8 +66,8 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje * @property {boolean} ignorePenumbra=false -

Deprecated: This property is deprecated and will be * removed.

*/ -void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions) { - if (!object.isObject()) { +void injectorOptionsFromScriptValue(const ScriptValuePointer& object, AudioInjectorOptions& injectorOptions) { + if (!object->isObject()) { qWarning() << "Audio injector options is not an object."; return; } @@ -77,53 +77,53 @@ void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOpt } injectorOptions.positionSet = false; - QScriptValueIterator it(object); - while (it.hasNext()) { - it.next(); + ScriptValueIteratorPointer it(object->newIterator()); + while (it->hasNext()) { + it->next(); - if (it.name() == "position") { - vec3FromScriptValue(object.property("position"), injectorOptions.position); + if (it->name() == "position") { + vec3FromScriptValue(object->property("position"), injectorOptions.position); injectorOptions.positionSet = true; - } else if (it.name() == "orientation") { - quatFromScriptValue(object.property("orientation"), injectorOptions.orientation); - } else if (it.name() == "volume") { - if (it.value().isNumber()) { - injectorOptions.volume = it.value().toNumber(); + } else if (it->name() == "orientation") { + quatFromScriptValue(object->property("orientation"), injectorOptions.orientation); + } else if (it->name() == "volume") { + if (it->value()->isNumber()) { + injectorOptions.volume = it->value()->toNumber(); } else { qCWarning(audio) << "Audio injector options: volume is not a number"; } - } else if (it.name() == "loop") { - if (it.value().isBool()) { - injectorOptions.loop = it.value().toBool(); + } else if (it->name() == "loop") { + if (it->value()->isBool()) { + injectorOptions.loop = it->value()->toBool(); } else { qCWarning(audio) << "Audio injector options: loop is not a boolean"; } - } else if (it.name() == "ignorePenumbra") { - if (it.value().isBool()) { - injectorOptions.ignorePenumbra = it.value().toBool(); + } else if (it->name() == "ignorePenumbra") { + if (it->value()->isBool()) { + injectorOptions.ignorePenumbra = it->value()->toBool(); } else { qCWarning(audio) << "Audio injector options: ignorePenumbra is not a boolean"; } - } else if (it.name() == "localOnly") { - if (it.value().isBool()) { - injectorOptions.localOnly = it.value().toBool(); + } else if (it->name() == "localOnly") { + if (it->value()->isBool()) { + injectorOptions.localOnly = it->value()->toBool(); } else { qCWarning(audio) << "Audio injector options: localOnly is not a boolean"; } - } else if (it.name() == "secondOffset") { - if (it.value().isNumber()) { - injectorOptions.secondOffset = it.value().toNumber(); + } else if (it->name() == "secondOffset") { + if (it->value()->isNumber()) { + injectorOptions.secondOffset = it->value()->toNumber(); } else { qCWarning(audio) << "Audio injector options: secondOffset is not a number"; } - } else if (it.name() == "pitch") { - if (it.value().isNumber()) { - injectorOptions.pitch = it.value().toNumber(); + } else if (it->name() == "pitch") { + if (it->value()->isNumber()) { + injectorOptions.pitch = it->value()->toNumber(); } else { qCWarning(audio) << "Audio injector options: pitch is not a number"; } } else { - qCWarning(audio) << "Unknown audio injector option:" << it.name(); + qCWarning(audio) << "Unknown audio injector option:" << it->name(); } } } diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index 5dec8a02403..3605bc2a068 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -12,10 +12,13 @@ #ifndef hifi_AudioInjectorOptions_h #define hifi_AudioInjectorOptions_h -#include - #include #include +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class AudioInjectorOptions { public: @@ -35,7 +38,7 @@ class AudioInjectorOptions { Q_DECLARE_METATYPE(AudioInjectorOptions); -QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions); -void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions); +ScriptValuePointer injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInjectorOptions& injectorOptions); +void injectorOptionsFromScriptValue(const ScriptValuePointer& object, AudioInjectorOptions& injectorOptions); #endif // hifi_AudioInjectorOptions_h diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 7c5dd3813bc..c6b68112285 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "AudioRingBuffer.h" #include "AudioLogging.h" @@ -422,12 +424,12 @@ SoundProcessor::AudioProperties SoundProcessor::interpretAsMP3(const QByteArray& } -QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) { - return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership); +ScriptValuePointer soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in) { + return engine->newQObject(new SoundScriptingInterface(in), ScriptEngine::ScriptOwnership); } -void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer& out) { - if (auto soundInterface = qobject_cast(object.toQObject())) { +void soundSharedPointerFromScriptValue(const ScriptValuePointer& object, SharedSoundPointer& out) { + if (auto soundInterface = qobject_cast(object->toQObject())) { out = soundInterface->getSound(); } } diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 205e1cba33f..f3e08dd1af4 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -15,14 +15,17 @@ #include #include #include -#include +#include #include #include "AudioConstants.h" class AudioData; +class ScriptEngine; +class ScriptValue; using AudioDataPointer = std::shared_ptr; +using ScriptValuePointer = QSharedPointer; Q_DECLARE_METATYPE(AudioDataPointer); @@ -168,7 +171,7 @@ class SoundScriptingInterface : public QObject { }; Q_DECLARE_METATYPE(SharedSoundPointer) -QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in); -void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer& out); +ScriptValuePointer soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in); +void soundSharedPointerFromScriptValue(const ScriptValuePointer& object, SharedSoundPointer& out); #endif // hifi_Sound_h diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index 0175d1113ae..a1a00582df0 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -1,18 +1,19 @@ set(TARGET_NAME avatars-renderer) -setup_hifi_library(Network Script) -link_hifi_libraries(shared shaders gpu graphics animation material-networking model-networking script-engine render render-utils image entities-renderer physics) +setup_hifi_library(Network) +link_hifi_libraries(shared shaders gpu graphics animation material-networking model-networking render render-utils image entities-renderer physics) +include_hifi_library_headers(audio) include_hifi_library_headers(avatars) -include_hifi_library_headers(networking) +include_hifi_library_headers(entities) +include_hifi_library_headers(graphics-scripting) # for ScriptableModel.h include_hifi_library_headers(hfm) -include_hifi_library_headers(model-serializers) -include_hifi_library_headers(recording) include_hifi_library_headers(ktx) -include_hifi_library_headers(procedural) -include_hifi_library_headers(audio) -include_hifi_library_headers(entities) +include_hifi_library_headers(model-serializers) +include_hifi_library_headers(networking) include_hifi_library_headers(octree) +include_hifi_library_headers(procedural) +include_hifi_library_headers(recording) +include_hifi_library_headers(script-engine) include_hifi_library_headers(task) include_hifi_library_headers(workload) -include_hifi_library_headers(graphics-scripting) # for ScriptableModel.h target_bullet() diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index fc6d15cced9..17d0b1dd3d4 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME avatars) -setup_hifi_library(Network Script) -link_hifi_libraries(shared networking) +setup_hifi_library(Network) +link_hifi_libraries(shared networking script-engine) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index c5085e927d7..2426ab2d619 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -35,11 +35,15 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include #include "AvatarLogging.h" #include "AvatarTraits.h" @@ -2534,69 +2538,69 @@ QDataStream& operator>>(QDataStream& in, AttachmentData& attachment) { } void AttachmentDataObject::setModelURL(const QString& modelURL) { - AttachmentData data = qscriptvalue_cast(thisObject()); + AttachmentData data = scriptvalue_cast(thisObject()); data.modelURL = modelURL; thisObject() = engine()->toScriptValue(data); } QString AttachmentDataObject::getModelURL() const { - return qscriptvalue_cast(thisObject()).modelURL.toString(); + return scriptvalue_cast(thisObject()).modelURL.toString(); } void AttachmentDataObject::setJointName(const QString& jointName) { - AttachmentData data = qscriptvalue_cast(thisObject()); + AttachmentData data = scriptvalue_cast(thisObject()); data.jointName = jointName; thisObject() = engine()->toScriptValue(data); } QString AttachmentDataObject::getJointName() const { - return qscriptvalue_cast(thisObject()).jointName; + return scriptvalue_cast(thisObject()).jointName; } void AttachmentDataObject::setTranslation(const glm::vec3& translation) { - AttachmentData data = qscriptvalue_cast(thisObject()); + AttachmentData data = scriptvalue_cast(thisObject()); data.translation = translation; thisObject() = engine()->toScriptValue(data); } glm::vec3 AttachmentDataObject::getTranslation() const { - return qscriptvalue_cast(thisObject()).translation; + return scriptvalue_cast(thisObject()).translation; } void AttachmentDataObject::setRotation(const glm::quat& rotation) { - AttachmentData data = qscriptvalue_cast(thisObject()); + AttachmentData data = scriptvalue_cast(thisObject()); data.rotation = rotation; thisObject() = engine()->toScriptValue(data); } glm::quat AttachmentDataObject::getRotation() const { - return qscriptvalue_cast(thisObject()).rotation; + return scriptvalue_cast(thisObject()).rotation; } void AttachmentDataObject::setScale(float scale) { - AttachmentData data = qscriptvalue_cast(thisObject()); + AttachmentData data = scriptvalue_cast(thisObject()); data.scale = scale; thisObject() = engine()->toScriptValue(data); } float AttachmentDataObject::getScale() const { - return qscriptvalue_cast(thisObject()).scale; + return scriptvalue_cast(thisObject()).scale; } void AttachmentDataObject::setIsSoft(bool isSoft) { - AttachmentData data = qscriptvalue_cast(thisObject()); + AttachmentData data = scriptvalue_cast(thisObject()); data.isSoft = isSoft; thisObject() = engine()->toScriptValue(data); } bool AttachmentDataObject::getIsSoft() const { - return qscriptvalue_cast(thisObject()).isSoft; + return scriptvalue_cast(thisObject()).isSoft; } -void registerAvatarTypes(QScriptEngine* engine) { - qScriptRegisterSequenceMetaType >(engine); +void registerAvatarTypes(ScriptEngine* engine) { + scriptRegisterSequenceMetaType >(engine); engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject( - new AttachmentDataObject(), QScriptEngine::ScriptOwnership)); + new AttachmentDataObject(), ScriptEngine::ScriptOwnership)); } void AvatarData::setRecordingBasis(std::shared_ptr recordingBasis) { @@ -3140,40 +3144,40 @@ glm::mat4 AvatarData::getControllerRightHandMatrix() const { * @property {SubmeshIntersection} extraInfo - Extra information on the mesh intersected if mesh was picked against, * {} if it wasn't. */ -QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& value) { - QScriptValue obj = engine->newObject(); - obj.setProperty("intersects", value.intersects); - QScriptValue avatarIDValue = quuidToScriptValue(engine, value.avatarID); - obj.setProperty("avatarID", avatarIDValue); - obj.setProperty("distance", value.distance); - obj.setProperty("face", boxFaceToString(value.face)); - QScriptValue intersection = vec3ToScriptValue(engine, value.intersection); - - obj.setProperty("intersection", intersection); - QScriptValue surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); - obj.setProperty("surfaceNormal", surfaceNormal); - obj.setProperty("jointIndex", value.jointIndex); - obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); +ScriptValuePointer RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, const RayToAvatarIntersectionResult& value) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("intersects", value.intersects); + ScriptValuePointer avatarIDValue = quuidToScriptValue(engine, value.avatarID); + obj->setProperty("avatarID", avatarIDValue); + obj->setProperty("distance", value.distance); + obj->setProperty("face", boxFaceToString(value.face)); + ScriptValuePointer intersection = vec3ToScriptValue(engine, value.intersection); + + obj->setProperty("intersection", intersection); + ScriptValuePointer surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); + obj->setProperty("surfaceNormal", surfaceNormal); + obj->setProperty("jointIndex", value.jointIndex); + obj->setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); return obj; } -void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, RayToAvatarIntersectionResult& value) { - value.intersects = object.property("intersects").toVariant().toBool(); - QScriptValue avatarIDValue = object.property("avatarID"); +void RayToAvatarIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToAvatarIntersectionResult& value) { + value.intersects = object->property("intersects")->toVariant().toBool(); + ScriptValuePointer avatarIDValue = object->property("avatarID"); quuidFromScriptValue(avatarIDValue, value.avatarID); - value.distance = object.property("distance").toVariant().toFloat(); - value.face = boxFaceFromString(object.property("face").toVariant().toString()); + value.distance = object->property("distance")->toVariant().toFloat(); + value.face = boxFaceFromString(object->property("face")->toVariant().toString()); - QScriptValue intersection = object.property("intersection"); - if (intersection.isValid()) { + ScriptValuePointer intersection = object->property("intersection"); + if (intersection->isValid()) { vec3FromScriptValue(intersection, value.intersection); } - QScriptValue surfaceNormal = object.property("surfaceNormal"); - if (surfaceNormal.isValid()) { + ScriptValuePointer surfaceNormal = object->property("surfaceNormal"); + if (surfaceNormal->isValid()) { vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } - value.jointIndex = object.property("jointIndex").toInt32(); - value.extraInfo = object.property("extraInfo").toVariant().toMap(); + value.jointIndex = object->property("jointIndex")->toInt32(); + value.extraInfo = object->property("extraInfo")->toVariant().toMap(); } // these coefficients can be changed via JS for experimental tuning @@ -3186,8 +3190,8 @@ float AvatarData::_avatarSortCoefficientAge { 1.0f }; * An object with the UUIDs of avatar entities as keys and avatar entity properties objects as values. * @typedef {Object.} AvatarEntityMap */ -QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value) { - QScriptValue obj = engine->newObject(); +ScriptValuePointer AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntityMap& value) { + ScriptValuePointer obj = engine->newObject(); for (auto entityID : value.keys()) { QByteArray entityProperties = value.value(entityID); QJsonDocument jsonEntityProperties = QJsonDocument::fromBinaryData(entityProperties); @@ -3197,22 +3201,22 @@ QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEnt QVariant variantEntityProperties = jsonEntityProperties.toVariant(); QVariantMap entityPropertiesMap = variantEntityProperties.toMap(); - QScriptValue scriptEntityProperties = variantMapToScriptValue(entityPropertiesMap, *engine); + ScriptValuePointer scriptEntityProperties = variantMapToScriptValue(entityPropertiesMap, *engine); QString key = entityID.toString(); - obj.setProperty(key, scriptEntityProperties); + obj->setProperty(key, scriptEntityProperties); } return obj; } -void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap& value) { - QScriptValueIterator itr(object); - while (itr.hasNext()) { - itr.next(); - QUuid EntityID = QUuid(itr.name()); +void AvatarEntityMapFromScriptValue(const ScriptValuePointer& object, AvatarEntityMap& value) { + ScriptValueIteratorPointer itr(object->newIterator()); + while (itr->hasNext()) { + itr->next(); + QUuid EntityID = QUuid(itr->name()); - QScriptValue scriptEntityProperties = itr.value(); - QVariant variantEntityProperties = scriptEntityProperties.toVariant(); + ScriptValuePointer scriptEntityProperties = itr->value(); + QVariant variantEntityProperties = scriptEntityProperties->toVariant(); QJsonDocument jsonEntityProperties = QJsonDocument::fromVariant(variantEntityProperties); QByteArray binaryEntityProperties = jsonEntityProperties.toBinaryData(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index b25a6938d73..cfecd448f88 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -31,9 +31,8 @@ #include #include #include -#include -#include #include +#include #include #include @@ -49,12 +48,17 @@ #include #include #include +#include "Scriptable.h" #include "AABox.h" #include "AvatarTraits.h" #include "HeadData.h" #include "PathUtils.h" +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; using AvatarHash = QHash; @@ -1924,7 +1928,7 @@ Q_DECLARE_METATYPE(AttachmentData) Q_DECLARE_METATYPE(QVector) /// Scriptable wrapper for attachments. -class AttachmentDataObject : public QObject, protected QScriptable { +class AttachmentDataObject : public QObject, protected Scriptable { Q_OBJECT Q_PROPERTY(QString modelURL READ getModelURL WRITE setModelURL) Q_PROPERTY(QString jointName READ getJointName WRITE setJointName) @@ -1954,7 +1958,7 @@ class AttachmentDataObject : public QObject, protected QScriptable { Q_INVOKABLE bool getIsSoft() const; }; -void registerAvatarTypes(QScriptEngine* engine); +void registerAvatarTypes(ScriptEngine* engine); class RayToAvatarIntersectionResult { public: @@ -1968,8 +1972,8 @@ class RayToAvatarIntersectionResult { QVariantMap extraInfo; }; Q_DECLARE_METATYPE(RayToAvatarIntersectionResult) -QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& results); -void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, RayToAvatarIntersectionResult& results); +ScriptValuePointer RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, const RayToAvatarIntersectionResult& results); +void RayToAvatarIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToAvatarIntersectionResult& results); // No JSDoc because it's not provided as a type to the script engine. class ParabolaToAvatarIntersectionResult { @@ -1986,8 +1990,8 @@ class ParabolaToAvatarIntersectionResult { Q_DECLARE_METATYPE(AvatarEntityMap) -QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value); -void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap& value); +ScriptValuePointer AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntityMap& value); +void AvatarEntityMapFromScriptValue(const ScriptValuePointer& object, AvatarEntityMap& value); // faux joint indexes (-1 means invalid) const int NO_JOINT_INDEX = 65535; // -1 diff --git a/libraries/baking/CMakeLists.txt b/libraries/baking/CMakeLists.txt index 12fb1928771..bfb989c05c6 100644 --- a/libraries/baking/CMakeLists.txt +++ b/libraries/baking/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME baking) setup_hifi_library(Concurrent) -link_hifi_libraries(shared shaders graphics networking procedural graphics-scripting ktx image model-serializers model-baker task) +link_hifi_libraries(shared shaders graphics networking procedural graphics-scripting ktx image model-serializers model-baker task script-engine) include_hifi_library_headers(gpu) include_hifi_library_headers(hfm) include_hifi_library_headers(material-networking) diff --git a/libraries/baking/src/MaterialBaker.cpp b/libraries/baking/src/MaterialBaker.cpp index 9a1b1b2d249..d5f1d652c51 100644 --- a/libraries/baking/src/MaterialBaker.cpp +++ b/libraries/baking/src/MaterialBaker.cpp @@ -20,6 +20,8 @@ #include #include +#include +#include #include @@ -28,6 +30,7 @@ std::function MaterialBaker::_getNextOvenWorkerThreadOperator; static int materialNum = 0; MaterialBaker::MaterialBaker(const QString& materialData, bool isURL, const QString& bakedOutputDir, QUrl destinationPath) : + _scriptEngine(newScriptEngine()), _materialData(materialData), _isURL(isURL), _destinationPath(destinationPath), @@ -209,13 +212,13 @@ void MaterialBaker::outputMaterial() { if (_materialResource->parsedMaterials.networkMaterials.size() == 1) { auto networkMaterial = _materialResource->parsedMaterials.networkMaterials.begin(); auto scriptableMaterial = scriptable::ScriptableMaterial(networkMaterial->second); - QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(&_scriptEngine, scriptableMaterial).toVariant(); + QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(_scriptEngine.data(), scriptableMaterial)->toVariant(); json.insert("materials", QJsonDocument::fromVariant(materialVariant).object()); } else { QJsonArray materialArray; for (auto networkMaterial : _materialResource->parsedMaterials.networkMaterials) { auto scriptableMaterial = scriptable::ScriptableMaterial(networkMaterial.second); - QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(&_scriptEngine, scriptableMaterial).toVariant(); + QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(_scriptEngine.data(), scriptableMaterial)->toVariant(); materialArray.append(QJsonDocument::fromVariant(materialVariant).object()); } json.insert("materials", materialArray); diff --git a/libraries/baking/src/MaterialBaker.h b/libraries/baking/src/MaterialBaker.h index 33123cfc732..44058521510 100644 --- a/libraries/baking/src/MaterialBaker.h +++ b/libraries/baking/src/MaterialBaker.h @@ -18,6 +18,7 @@ #include "baking/TextureFileNamer.h" #include +#include static const QString BAKED_MATERIAL_EXTENSION = ".baked.json"; @@ -67,7 +68,7 @@ private slots: QString _textureOutputDir; QString _bakedMaterialData; - QScriptEngine _scriptEngine; + ScriptEnginePointer _scriptEngine; static std::function _getNextOvenWorkerThreadOperator; TextureFileNamer _textureFileNamer; diff --git a/libraries/controllers/CMakeLists.txt b/libraries/controllers/CMakeLists.txt index 9c6bbf4aaeb..ee1fc1d1630 100644 --- a/libraries/controllers/CMakeLists.txt +++ b/libraries/controllers/CMakeLists.txt @@ -1,10 +1,10 @@ set(TARGET_NAME controllers) # set a default root dir for each of our optional externals if it was not passed -setup_hifi_library(Script Qml) +setup_hifi_library(Qml) # use setup_hifi_library macro to setup our project and link appropriate Qt modules -link_hifi_libraries(shared) +link_hifi_libraries(shared script-engine) include_hifi_library_headers(networking) GroupSources("src/controllers") diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index 6df4b4af818..c5968d65365 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -8,10 +8,11 @@ #include "Pose.h" -#include -#include +#include +#include #include +#include namespace controller { @@ -39,25 +40,25 @@ namespace controller { * @property {Vec3} angularVelocity - Angular velocity in rad/s. * @property {boolean} valid - true if the pose is valid, otherwise false. */ - QScriptValue Pose::toScriptValue(QScriptEngine* engine, const Pose& pose) { - QScriptValue obj = engine->newObject(); - obj.setProperty("translation", vec3ToScriptValue(engine, pose.translation)); - obj.setProperty("rotation", quatToScriptValue(engine, pose.rotation)); - obj.setProperty("velocity", vec3ToScriptValue(engine, pose.velocity)); - obj.setProperty("angularVelocity", vec3ToScriptValue(engine, pose.angularVelocity)); - obj.setProperty("valid", pose.valid); + ScriptValuePointer Pose::toScriptValue(ScriptEngine* engine, const Pose& pose) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("translation", vec3ToScriptValue(engine, pose.translation)); + obj->setProperty("rotation", quatToScriptValue(engine, pose.rotation)); + obj->setProperty("velocity", vec3ToScriptValue(engine, pose.velocity)); + obj->setProperty("angularVelocity", vec3ToScriptValue(engine, pose.angularVelocity)); + obj->setProperty("valid", pose.valid); return obj; } - void Pose::fromScriptValue(const QScriptValue& object, Pose& pose) { - auto translation = object.property("translation"); - auto rotation = object.property("rotation"); - auto velocity = object.property("velocity"); - auto angularVelocity = object.property("angularVelocity"); - if (translation.isValid() && - rotation.isValid() && - velocity.isValid() && - angularVelocity.isValid()) { + void Pose::fromScriptValue(const ScriptValuePointer& object, Pose& pose) { + auto translation = object->property("translation"); + auto rotation = object->property("rotation"); + auto velocity = object->property("velocity"); + auto angularVelocity = object->property("angularVelocity"); + if (translation->isValid() && + rotation->isValid() && + velocity->isValid() && + angularVelocity->isValid()) { vec3FromScriptValue(translation, pose.translation); quatFromScriptValue(rotation, pose.rotation); vec3FromScriptValue(velocity, pose.velocity); diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h index 186bbdd7339..0dff0293d15 100644 --- a/libraries/controllers/src/controllers/Pose.h +++ b/libraries/controllers/src/controllers/Pose.h @@ -10,9 +10,11 @@ #pragma once #ifndef hifi_controllers_Pose_h #define hifi_controllers_Pose_h +#include -class QScriptEngine; -class QScriptValue; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; #include @@ -44,8 +46,8 @@ namespace controller { Pose transform(const glm::mat4& mat) const; Pose postTransform(const glm::mat4& mat) const; - static QScriptValue toScriptValue(QScriptEngine* engine, const Pose& event); - static void fromScriptValue(const QScriptValue& object, Pose& event); + static ScriptValuePointer toScriptValue(ScriptEngine* engine, const Pose& event); + static void fromScriptValue(const ScriptValuePointer& object, Pose& event); }; } diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 076146a79dc..da3ac8461b1 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -29,7 +29,6 @@ #include #include -#include #include #include diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 6333792b3f1..101ce9e0f97 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -26,6 +26,10 @@ #include "StateController.h" #include "InputRecorder.h" #include "Logging.h" +#include "ScriptValueUtils.h" +#include +#include +#include #include "impl/conditionals/AndConditional.h" #include "impl/conditionals/NotConditional.h" @@ -388,69 +392,69 @@ int inputPairMetaTypeId = qRegisterMetaType(); int poseMetaTypeId = qRegisterMetaType("Pose"); int handMetaTypeId = qRegisterMetaType(); -QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input); -void inputFromScriptValue(const QScriptValue& object, Input& input); -QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action); -void actionFromScriptValue(const QScriptValue& object, Action& action); -QScriptValue inputPairToScriptValue(QScriptEngine* engine, const Input::NamedPair& inputPair); -void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inputPair); -QScriptValue handToScriptValue(QScriptEngine* engine, const controller::Hand& hand); -void handFromScriptValue(const QScriptValue& object, controller::Hand& hand); - -QScriptValue inputToScriptValue(QScriptEngine* engine, const Input& input) { - QScriptValue obj = engine->newObject(); - obj.setProperty("device", input.getDevice()); - obj.setProperty("channel", input.getChannel()); - obj.setProperty("type", (unsigned short)input.getType()); - obj.setProperty("id", input.getID()); +ScriptValuePointer inputToScriptValue(ScriptEngine* engine, const Input& input); +void inputFromScriptValue(const ScriptValuePointer& object, Input& input); +ScriptValuePointer actionToScriptValue(ScriptEngine* engine, const Action& action); +void actionFromScriptValue(const ScriptValuePointer& object, Action& action); +ScriptValuePointer inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair); +void inputPairFromScriptValue(const ScriptValuePointer& object, Input::NamedPair& inputPair); +ScriptValuePointer handToScriptValue(ScriptEngine* engine, const controller::Hand& hand); +void handFromScriptValue(const ScriptValuePointer& object, controller::Hand& hand); + +ScriptValuePointer inputToScriptValue(ScriptEngine* engine, const Input& input) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("device", input.getDevice()); + obj->setProperty("channel", input.getChannel()); + obj->setProperty("type", (unsigned short)input.getType()); + obj->setProperty("id", input.getID()); return obj; } -void inputFromScriptValue(const QScriptValue& object, Input& input) { - input.id = object.property("id").toInt32(); +void inputFromScriptValue(const ScriptValuePointer& object, Input& input) { + input.id = object->property("id")->toInt32(); } -QScriptValue actionToScriptValue(QScriptEngine* engine, const Action& action) { - QScriptValue obj = engine->newObject(); +ScriptValuePointer actionToScriptValue(ScriptEngine* engine, const Action& action) { + ScriptValuePointer obj = engine->newObject(); auto userInputMapper = DependencyManager::get(); - obj.setProperty("action", (int)action); - obj.setProperty("actionName", userInputMapper->getActionName(action)); + obj->setProperty("action", (int)action); + obj->setProperty("actionName", userInputMapper->getActionName(action)); return obj; } -void actionFromScriptValue(const QScriptValue& object, Action& action) { - action = Action(object.property("action").toVariant().toInt()); +void actionFromScriptValue(const ScriptValuePointer& object, Action& action) { + action = Action(object->property("action")->toVariant().toInt()); } -QScriptValue inputPairToScriptValue(QScriptEngine* engine, const Input::NamedPair& inputPair) { - QScriptValue obj = engine->newObject(); - obj.setProperty("input", inputToScriptValue(engine, inputPair.first)); - obj.setProperty("inputName", inputPair.second); +ScriptValuePointer inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("input", inputToScriptValue(engine, inputPair.first)); + obj->setProperty("inputName", inputPair.second); return obj; } -void inputPairFromScriptValue(const QScriptValue& object, Input::NamedPair& inputPair) { - inputFromScriptValue(object.property("input"), inputPair.first); - inputPair.second = QString(object.property("inputName").toVariant().toString()); +void inputPairFromScriptValue(const ScriptValuePointer& object, Input::NamedPair& inputPair) { + inputFromScriptValue(object->property("input"), inputPair.first); + inputPair.second = QString(object->property("inputName")->toVariant().toString()); } -QScriptValue handToScriptValue(QScriptEngine* engine, const controller::Hand& hand) { - return engine->newVariant((int)hand); +ScriptValuePointer handToScriptValue(ScriptEngine* engine, const controller::Hand& hand) { + return engine->newValue((int)hand); } -void handFromScriptValue(const QScriptValue& object, controller::Hand& hand) { - hand = Hand(object.toVariant().toInt()); +void handFromScriptValue(const ScriptValuePointer& object, controller::Hand& hand) { + hand = Hand(object->toVariant().toInt()); } -void UserInputMapper::registerControllerTypes(QScriptEngine* engine) { - qScriptRegisterSequenceMetaType >(engine); - qScriptRegisterSequenceMetaType(engine); - qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue); - qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); - qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); - qScriptRegisterMetaType(engine, handToScriptValue, handFromScriptValue); +void UserInputMapper::registerControllerTypes(ScriptEngine* engine) { + scriptRegisterSequenceMetaType >(engine); + scriptRegisterSequenceMetaType(engine); + scriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue); + scriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue); + scriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue); + scriptRegisterMetaType(engine, handToScriptValue, handFromScriptValue); - qScriptRegisterMetaType(engine, Pose::toScriptValue, Pose::fromScriptValue); + scriptRegisterMetaType(engine, Pose::toScriptValue, Pose::fromScriptValue); } Input UserInputMapper::makeStandardInput(controller::StandardButtonChannel button) { @@ -658,21 +662,21 @@ Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) { return Endpoint::Pointer(); } -Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) { - if (endpoint.isNumber()) { - return endpointFor(Input(endpoint.toInt32())); +Endpoint::Pointer UserInputMapper::endpointFor(const ScriptValuePointer& endpoint) { + if (endpoint->isNumber()) { + return endpointFor(Input(endpoint->toInt32())); } - if (endpoint.isFunction()) { + if (endpoint->isFunction()) { auto result = std::make_shared(endpoint); return result; } - if (endpoint.isArray()) { - int length = endpoint.property("length").toInteger(); + if (endpoint->isArray()) { + int length = endpoint->property("length")->toInteger(); Endpoint::List children; for (int i = 0; i < length; i++) { - QScriptValue arrayItem = endpoint.property(i); + ScriptValuePointer arrayItem = endpoint->property(i); Endpoint::Pointer destination = endpointFor(arrayItem); if (!destination) { return Endpoint::Pointer(); @@ -683,7 +687,7 @@ Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) { } - qWarning() << "Unsupported input type " << endpoint.toString(); + qWarning() << "Unsupported input type " << endpoint->toString(); return Endpoint::Pointer(); } @@ -883,12 +887,12 @@ Conditional::Pointer UserInputMapper::conditionalFor(const QJSValue& condition) return Conditional::Pointer(); } -Conditional::Pointer UserInputMapper::conditionalFor(const QScriptValue& condition) { - if (condition.isArray()) { - int length = condition.property("length").toInteger(); +Conditional::Pointer UserInputMapper::conditionalFor(const ScriptValuePointer& condition) { + if (condition->isArray()) { + int length = condition->property("length")->toInteger(); Conditional::List children; for (int i = 0; i < length; i++) { - Conditional::Pointer destination = conditionalFor(condition.property(i)); + Conditional::Pointer destination = conditionalFor(condition->property(i)); if (!destination) { return Conditional::Pointer(); } @@ -897,15 +901,15 @@ Conditional::Pointer UserInputMapper::conditionalFor(const QScriptValue& conditi return std::make_shared(children); } - if (condition.isNumber()) { - return conditionalFor(Input(condition.toInt32())); + if (condition->isNumber()) { + return conditionalFor(Input(condition->toInt32())); } - if (condition.isFunction()) { + if (condition->isFunction()) { return std::make_shared(condition); } - qWarning() << "Unsupported conditional type " << condition.toString(); + qWarning() << "Unsupported conditional type " << condition->toString(); return Conditional::Pointer(); } diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index ee8b34193fb..6e67ca22ee4 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -16,9 +16,9 @@ #include #include #include +#include #include -#include #include #include @@ -32,6 +32,10 @@ #include "Actions.h" #include "StateController.h" +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + namespace controller { class RouteBuilderProxy; @@ -64,7 +68,7 @@ namespace controller { virtual ~UserInputMapper(); - static void registerControllerTypes(QScriptEngine* engine); + static void registerControllerTypes(ScriptEngine* engine); void registerDevice(InputDevice::Pointer device); InputDevice::Pointer getDevice(const Input& input); @@ -164,10 +168,10 @@ namespace controller { void enableMapping(const MappingPointer& mapping); void disableMapping(const MappingPointer& mapping); EndpointPointer endpointFor(const QJSValue& endpoint); - EndpointPointer endpointFor(const QScriptValue& endpoint); + EndpointPointer endpointFor(const ScriptValuePointer& endpoint); EndpointPointer compositeEndpointFor(EndpointPointer first, EndpointPointer second); ConditionalPointer conditionalFor(const QJSValue& endpoint); - ConditionalPointer conditionalFor(const QScriptValue& endpoint); + ConditionalPointer conditionalFor(const ScriptValuePointer& endpoint); ConditionalPointer conditionalFor(const Input& endpoint) const; MappingPointer parseMapping(const QJsonValue& json); diff --git a/libraries/controllers/src/controllers/impl/Endpoint.h b/libraries/controllers/src/controllers/impl/Endpoint.h index 692e427e165..00a4c264a9b 100644 --- a/libraries/controllers/src/controllers/impl/Endpoint.h +++ b/libraries/controllers/src/controllers/impl/Endpoint.h @@ -20,8 +20,6 @@ #include "../Input.h" #include "../Pose.h" -class QScriptValue; - namespace controller { /* * Encapsulates a particular input / output, diff --git a/libraries/controllers/src/controllers/impl/Filter.cpp b/libraries/controllers/src/controllers/impl/Filter.cpp index f230fb83dc9..2a175137036 100644 --- a/libraries/controllers/src/controllers/impl/Filter.cpp +++ b/libraries/controllers/src/controllers/impl/Filter.cpp @@ -9,7 +9,6 @@ #include "Filter.h" #include -#include #include #include diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp index 1af3f271bea..d82aece9e94 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp @@ -17,6 +17,7 @@ #include "RouteBuilderProxy.h" #include "../ScriptingInterface.h" #include "../Logging.h" +#include using namespace controller; @@ -26,8 +27,8 @@ QObject* MappingBuilderProxy::fromQml(const QJSValue& source) { return from(sourceEndpoint); } -QObject* MappingBuilderProxy::from(const QScriptValue& source) { - qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString(); +QObject* MappingBuilderProxy::from(const ScriptValuePointer& source) { + qCDebug(controllers) << "Creating new Route builder proxy from " << source->toString(); auto sourceEndpoint = _parent.endpointFor(source); return from(sourceEndpoint); } @@ -49,7 +50,7 @@ QObject* MappingBuilderProxy::makeAxisQml(const QJSValue& source1, const QJSValu return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint)); } -QObject* MappingBuilderProxy::makeAxis(const QScriptValue& source1, const QScriptValue& source2) { +QObject* MappingBuilderProxy::makeAxis(const ScriptValuePointer& source1, const ScriptValuePointer& source2) { auto source1Endpoint = _parent.endpointFor(source1); auto source2Endpoint = _parent.endpointFor(source2); return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint)); diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h index 9dafc03f1f6..83d2f94877a 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -11,13 +11,15 @@ #include #include +#include #include "Mapping.h" #include "Endpoint.h" class QJSValue; -class QScriptValue; class QJsonValue; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; namespace controller { @@ -165,7 +167,7 @@ class MappingBuilderProxy : public QObject { * of the route data. If a function, it must return a number or a {@link Pose} value as the route data. * @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods. */ - Q_INVOKABLE QObject* from(const QScriptValue& source); + Q_INVOKABLE QObject* from(const ScriptValuePointer& source); /**jsdoc * Creates a new {@link RouteObject} from two numeric {@link Controller.Hardware} outputs, one applied in the negative @@ -187,7 +189,7 @@ class MappingBuilderProxy : public QObject { * Controller.disableMapping(MAPPING_NAME); * }); */ - Q_INVOKABLE QObject* makeAxis(const QScriptValue& source1, const QScriptValue& source2); + Q_INVOKABLE QObject* makeAxis(const ScriptValuePointer& source1, const ScriptValuePointer& source2); /**jsdoc * Enables or disables the mapping. When enabled, the routes in the mapping take effect. diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp index 56ace233357..49308c6e412 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp @@ -17,6 +17,7 @@ #include "MappingBuilderProxy.h" #include "../ScriptingInterface.h" #include "../Logging.h" +#include #include "filters/ClampFilter.h" #include "filters/ConstrainToIntegerFilter.h" @@ -43,8 +44,8 @@ void RouteBuilderProxy::toQml(const QJSValue& destination) { return to(destinationEndpoint); } -void RouteBuilderProxy::to(const QScriptValue& destination) { - qCDebug(controllers) << "Completing route " << destination.toString(); +void RouteBuilderProxy::to(const ScriptValuePointer& destination) { + qCDebug(controllers) << "Completing route " << destination->toString(); auto destinationEndpoint = _parent.endpointFor(destination); return to(destinationEndpoint); } @@ -65,7 +66,7 @@ QObject* RouteBuilderProxy::peek(bool enable) { return this; } -QObject* RouteBuilderProxy::when(const QScriptValue& expression) { +QObject* RouteBuilderProxy::when(const ScriptValuePointer& expression) { // FIXME: Support "!" conditional in simple expression and array expression. // Note that "!" is supported when parsing a JSON file, in UserInputMapper::parseConditional(). auto newConditional = _parent.conditionalFor(expression); diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index 38b18346a81..a158334c005 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -10,6 +10,7 @@ #define hifi_Controllers_Impl_RouteBuilderProxy_h #include +#include #include "Filter.h" #include "Route.h" @@ -18,8 +19,9 @@ #include "../UserInputMapper.h" class QJSValue; -class QScriptValue; class QJsonValue; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; namespace controller { @@ -115,7 +117,7 @@ class RouteBuilderProxy : public QObject { * Controller.disableMapping(MAPPING_NAME); * }); */ - Q_INVOKABLE void to(const QScriptValue& destination); + Q_INVOKABLE void to(const ScriptValuePointer& destination); /**jsdoc * Enables or disables writing debug information for a route to the program log. @@ -193,7 +195,7 @@ class RouteBuilderProxy : public QObject { * Controller.disableMapping(MAPPING_NAME); * }); */ - Q_INVOKABLE QObject* when(const QScriptValue& expression); + Q_INVOKABLE QObject* when(const ScriptValuePointer& expression); /**jsdoc * Filters numeric route values to lie between two values; values outside this range are not passed on through the diff --git a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp index 277b63ed112..d868ad343ef 100644 --- a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp +++ b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp @@ -10,6 +10,8 @@ #include +#include + using namespace controller; bool ScriptConditional::satisfied() { @@ -23,5 +25,5 @@ void ScriptConditional::updateValue() { return; } - _lastValue = _callable.call().toBool(); + _lastValue = _callable->call()->toBool(); } diff --git a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h index 800692d02c7..0ac4cc4434d 100644 --- a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h +++ b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h @@ -11,22 +11,24 @@ #define hifi_Controllers_ScriptConditional_h #include - -#include +#include #include "../Conditional.h" +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + namespace controller { class ScriptConditional : public QObject, public Conditional { Q_OBJECT; public: - ScriptConditional(const QScriptValue& callable) : _callable(callable) { } + ScriptConditional(const ScriptValuePointer& callable) : _callable(callable) {} virtual bool satisfied() override; protected: Q_INVOKABLE void updateValue(); private: - QScriptValue _callable; + ScriptValuePointer _callable; bool _lastValue { false }; }; diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp index 9f971d2f04c..90184afd230 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp @@ -11,18 +11,20 @@ #include +#include +#include #include using namespace controller; -QString formatException(const QScriptValue& exception) { +QString formatException(const ScriptValuePointer& exception) { QString note { "UncaughtException" }; QString result; - const auto message = exception.toString(); - const auto fileName = exception.property("fileName").toString(); - const auto lineNumber = exception.property("lineNumber").toString(); - const auto stacktrace = exception.property("stack").toString(); + const auto message = exception->toString(); + const auto fileName = exception->property("fileName")->toString(); + const auto lineNumber = exception->property("lineNumber")->toString(); + const auto stacktrace = exception->property("stack")->toString(); const QString SCRIPT_EXCEPTION_FORMAT = "[%0] %1 in %2:%3"; const QString SCRIPT_BACKTRACE_SEP = "\n "; @@ -45,13 +47,13 @@ void ScriptEndpoint::updateValue() { return; } - QScriptValue result = _callable.call(); - if (result.isError()) { + ScriptValuePointer result = _callable->call(); + if (result->isError()) { // print JavaScript exception qCDebug(controllers).noquote() << formatException(result); _lastValueRead = 0.0f; - } else if (result.isNumber()) { - _lastValueRead = (float)_callable.call().toNumber(); + } else if (result->isNumber()) { + _lastValueRead = (float)_callable->call()->toNumber(); } else { Pose::fromScriptValue(result, _lastPoseRead); _returnPose = true; @@ -73,9 +75,10 @@ void ScriptEndpoint::internalApply(float value, int sourceID) { Q_ARG(int, sourceID)); return; } - QScriptValue result = _callable.call(QScriptValue(), - QScriptValueList({ QScriptValue(value), QScriptValue(sourceID) })); - if (result.isError()) { + ScriptEnginePointer engine = _callable->engine(); + ScriptValuePointer result = _callable->call(ScriptValuePointer(), + ScriptValueList({ engine->newValue(value), engine->newValue(sourceID) })); + if (result->isError()) { // print JavaScript exception qCDebug(controllers).noquote() << formatException(result); } @@ -91,8 +94,8 @@ void ScriptEndpoint::updatePose() { QMetaObject::invokeMethod(this, "updatePose", Qt::QueuedConnection); return; } - QScriptValue result = _callable.call(); - if (result.isError()) { + ScriptValuePointer result = _callable->call(); + if (result->isError()) { // print JavaScript exception qCDebug(controllers).noquote() << formatException(result); } @@ -114,9 +117,10 @@ void ScriptEndpoint::internalApply(const Pose& newPose, int sourceID) { Q_ARG(int, sourceID)); return; } - QScriptValue result = _callable.call(QScriptValue(), - QScriptValueList({ Pose::toScriptValue(_callable.engine(), newPose), QScriptValue(sourceID) })); - if (result.isError()) { + ScriptEnginePointer engine = _callable->engine(); + ScriptValuePointer result = _callable->call(ScriptValuePointer(), + ScriptValueList({ Pose::toScriptValue(engine.get(), newPose), engine->newValue(sourceID) })); + if (result->isError()) { // print JavaScript exception qCDebug(controllers).noquote() << formatException(result); } diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h index 1aa1746b249..ff42812c4b2 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h @@ -10,17 +10,20 @@ #ifndef hifi_Controllers_ScriptEndpoint_h #define hifi_Controllers_ScriptEndpoint_h -#include +#include #include "../Endpoint.h" +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + namespace controller { class ScriptEndpoint : public Endpoint { Q_OBJECT; public: using Endpoint::apply; - ScriptEndpoint(const QScriptValue& callable) + ScriptEndpoint(const ScriptValuePointer& callable) : Endpoint(Input::INVALID_INPUT), _callable(callable) { } @@ -39,7 +42,7 @@ class ScriptEndpoint : public Endpoint { Q_INVOKABLE void updatePose(); Q_INVOKABLE virtual void internalApply(const Pose& newValue, int sourceID); private: - QScriptValue _callable; + ScriptValuePointer _callable; float _lastValueRead { 0.0f }; AxisValue _lastValueWritten { 0.0f, 0, false }; diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 5f40c8d5fe8..22c0f7ee45a 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,20 +1,20 @@ set(TARGET_NAME entities-renderer) -setup_hifi_library(Network Script) +setup_hifi_library(Network) link_hifi_libraries(shared workload gpu shaders procedural graphics material-networking model-networking script-engine render render-utils image qml ui pointers) -include_hifi_library_headers(networking) +include_hifi_library_headers(animation) +include_hifi_library_headers(audio) +include_hifi_library_headers(avatars) +include_hifi_library_headers(controllers) +include_hifi_library_headers(entities) include_hifi_library_headers(gl) +include_hifi_library_headers(graphics-scripting) # for Forward.h +include_hifi_library_headers(hfm) include_hifi_library_headers(ktx) +include_hifi_library_headers(model-serializers) +include_hifi_library_headers(networking) include_hifi_library_headers(octree) -include_hifi_library_headers(audio) include_hifi_library_headers(physics) -include_hifi_library_headers(animation) -include_hifi_library_headers(hfm) -include_hifi_library_headers(model-serializers) -include_hifi_library_headers(entities) -include_hifi_library_headers(avatars) -include_hifi_library_headers(controllers) include_hifi_library_headers(task) -include_hifi_library_headers(graphics-scripting) # for Forward.h target_bullet() target_polyvox() diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 1504afdebee..4662fa2ad06 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -158,45 +158,45 @@ render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& i int EntityTreeRenderer::_entitiesScriptEngineCount = 0; -void EntityTreeRenderer::setupEntityScriptEngineSignals(const ScriptEnginePointer& scriptEngine) { +void EntityTreeRenderer::setupEntityScriptEngineSignals(const ScriptManagerPointer& scriptManager) { auto entityScriptingInterface = DependencyManager::get(); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "mousePressOnEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "mousePressOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseDoublePressOnEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "mouseDoublePressOnEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseDoublePressOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "mouseDoublePressOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "mouseMoveOnEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "mouseMoveOnEntity", event); // FIXME: this is a duplicate of mouseMoveOnEntity, but it seems like some scripts might use this naming - scriptEngine->callEntityScriptMethod(entityID, "mouseMoveEvent", event); + scriptManager->callEntityScriptMethod(entityID, "mouseMoveEvent", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "mouseReleaseOnEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "mouseReleaseOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "clickDownOnEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "clickDownOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::holdingClickOnEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "holdingClickOnEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::holdingClickOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "holdingClickOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickReleaseOnEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "clickReleaseOnEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickReleaseOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "clickReleaseOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "hoverEnterEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "hoverEnterEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "hoverOverEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "hoverOverEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, scriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { - scriptEngine->callEntityScriptMethod(entityID, "hoverLeaveEntity", event); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + scriptManager->callEntityScriptMethod(entityID, "hoverLeaveEntity", event); }); - connect(scriptEngine.data(), &ScriptEngine::entityScriptPreloadFinished, [&](const EntityItemID& entityID) { + connect(scriptManager.data(), &ScriptManager::entityScriptPreloadFinished, [&](const EntityItemID& entityID) { EntityItemPointer entity = getTree()->findEntityByID(entityID); if (entity) { entity->setScriptHasFinishedPreload(true); @@ -205,51 +205,51 @@ void EntityTreeRenderer::setupEntityScriptEngineSignals(const ScriptEnginePointe } void EntityTreeRenderer::resetPersistentEntitiesScriptEngine() { - if (_persistentEntitiesScriptEngine) { - _persistentEntitiesScriptEngine->unloadAllEntityScripts(true); - _persistentEntitiesScriptEngine->stop(); - _persistentEntitiesScriptEngine->waitTillDoneRunning(); - _persistentEntitiesScriptEngine->disconnectNonEssentialSignals(); + if (_persistentEntitiesScriptManager) { + _persistentEntitiesScriptManager->unloadAllEntityScripts(true); + _persistentEntitiesScriptManager->stop(); + _persistentEntitiesScriptManager->waitTillDoneRunning(); + _persistentEntitiesScriptManager->disconnectNonEssentialSignals(); } - _persistentEntitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, + _persistentEntitiesScriptManager = scriptManagerFactory(ScriptManager::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); - DependencyManager::get()->runScriptInitializers(_persistentEntitiesScriptEngine); - _persistentEntitiesScriptEngine->runInThread(); - auto entitiesScriptEngineProvider = qSharedPointerCast(_persistentEntitiesScriptEngine); + DependencyManager::get()->runScriptInitializers(_persistentEntitiesScriptManager); + _persistentEntitiesScriptManager->runInThread(); + auto entitiesScriptEngineProvider = qSharedPointerCast(_persistentEntitiesScriptManager); auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->setPersistentEntitiesScriptEngine(entitiesScriptEngineProvider); - setupEntityScriptEngineSignals(_persistentEntitiesScriptEngine); + setupEntityScriptEngineSignals(_persistentEntitiesScriptManager); } void EntityTreeRenderer::resetNonPersistentEntitiesScriptEngine() { - if (_nonPersistentEntitiesScriptEngine) { - _nonPersistentEntitiesScriptEngine->unloadAllEntityScripts(true); - _nonPersistentEntitiesScriptEngine->stop(); - _nonPersistentEntitiesScriptEngine->waitTillDoneRunning(); - _nonPersistentEntitiesScriptEngine->disconnectNonEssentialSignals(); + if (_nonPersistentEntitiesScriptManager) { + _nonPersistentEntitiesScriptManager->unloadAllEntityScripts(true); + _nonPersistentEntitiesScriptManager->stop(); + _nonPersistentEntitiesScriptManager->waitTillDoneRunning(); + _nonPersistentEntitiesScriptManager->disconnectNonEssentialSignals(); } - _nonPersistentEntitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, + _nonPersistentEntitiesScriptManager = scriptManagerFactory(ScriptManager::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); - DependencyManager::get()->runScriptInitializers(_nonPersistentEntitiesScriptEngine); - _nonPersistentEntitiesScriptEngine->runInThread(); - auto entitiesScriptEngineProvider = qSharedPointerCast(_nonPersistentEntitiesScriptEngine); + DependencyManager::get()->runScriptInitializers(_nonPersistentEntitiesScriptManager); + _nonPersistentEntitiesScriptManager->runInThread(); + auto entitiesScriptEngineProvider = qSharedPointerCast(_nonPersistentEntitiesScriptManager); DependencyManager::get()->setNonPersistentEntitiesScriptEngine(entitiesScriptEngineProvider); - setupEntityScriptEngineSignals(_nonPersistentEntitiesScriptEngine); + setupEntityScriptEngineSignals(_nonPersistentEntitiesScriptManager); } void EntityTreeRenderer::stopDomainAndNonOwnedEntities() { leaveDomainAndNonOwnedEntities(); // unload and stop the engine - if (_nonPersistentEntitiesScriptEngine) { - QList entitiesWithEntityScripts = _nonPersistentEntitiesScriptEngine->getListOfEntityScriptIDs(); + if (_nonPersistentEntitiesScriptManager) { + QList entitiesWithEntityScripts = _nonPersistentEntitiesScriptManager->getListOfEntityScriptIDs(); foreach (const EntityItemID& entityID, entitiesWithEntityScripts) { EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); if (entityItem && !entityItem->getScript().isEmpty()) { if (!(entityItem->isLocalEntity() || entityItem->isMyAvatarEntity())) { - _nonPersistentEntitiesScriptEngine->unloadEntityScript(entityID, true); + _nonPersistentEntitiesScriptManager->unloadEntityScript(entityID, true); } } } @@ -297,15 +297,15 @@ void EntityTreeRenderer::clear() { auto scene = _viewState->getMain3DScene(); if (_shuttingDown) { // unload and stop the engines - if (_nonPersistentEntitiesScriptEngine) { + if (_nonPersistentEntitiesScriptManager) { // do this here (instead of in deleter) to avoid marshalling unload signals back to this thread - _nonPersistentEntitiesScriptEngine->unloadAllEntityScripts(true); - _nonPersistentEntitiesScriptEngine->stop(); + _nonPersistentEntitiesScriptManager->unloadAllEntityScripts(true); + _nonPersistentEntitiesScriptManager->stop(); } - if (_persistentEntitiesScriptEngine) { + if (_persistentEntitiesScriptManager) { // do this here (instead of in deleter) to avoid marshalling unload signals back to this thread - _persistentEntitiesScriptEngine->unloadAllEntityScripts(true); - _persistentEntitiesScriptEngine->stop(); + _persistentEntitiesScriptManager->unloadAllEntityScripts(true); + _persistentEntitiesScriptManager->stop(); } if (scene) { @@ -343,16 +343,16 @@ void EntityTreeRenderer::clear() { } void EntityTreeRenderer::reloadEntityScripts() { - _persistentEntitiesScriptEngine->unloadAllEntityScripts(); - _persistentEntitiesScriptEngine->resetModuleCache(); - _nonPersistentEntitiesScriptEngine->unloadAllEntityScripts(); - _nonPersistentEntitiesScriptEngine->resetModuleCache(); + _persistentEntitiesScriptManager->unloadAllEntityScripts(); + _persistentEntitiesScriptManager->resetModuleCache(); + _nonPersistentEntitiesScriptManager->unloadAllEntityScripts(); + _nonPersistentEntitiesScriptManager->resetModuleCache(); for (const auto& entry : _entitiesInScene) { const auto& renderer = entry.second; const auto& entity = renderer->getEntity(); if (entity && !entity->getScript().isEmpty()) { - auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; scriptEngine->loadEntityScript(entity->getEntityItemID(), resolveScriptURL(entity->getScript()), true); } } @@ -376,11 +376,11 @@ void EntityTreeRenderer::init() { } void EntityTreeRenderer::shutdown() { - if (_persistentEntitiesScriptEngine) { - _persistentEntitiesScriptEngine->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential + if (_persistentEntitiesScriptManager) { + _persistentEntitiesScriptManager->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential } - if (_nonPersistentEntitiesScriptEngine) { - _nonPersistentEntitiesScriptEngine->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential + if (_nonPersistentEntitiesScriptManager) { + _nonPersistentEntitiesScriptManager->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential } _shuttingDown = true; @@ -696,14 +696,14 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { // EntityItemIDs from here. The callEntityScriptMethod() method is robust against attempting to call scripts // for entity IDs that no longer exist. - if (_persistentEntitiesScriptEngine && _nonPersistentEntitiesScriptEngine) { + if (_persistentEntitiesScriptManager && _nonPersistentEntitiesScriptManager) { // for all of our previous containing entities, if they are no longer containing then send them a leave event foreach(const EntityItemID& entityID, _currentEntitiesInside) { if (!entitiesContainingAvatar.contains(entityID)) { emit leaveEntity(entityID); auto entity = getTree()->findEntityByEntityItemID(entityID); if (entity) { - auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; scriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); } } @@ -715,7 +715,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { emit enterEntity(entityID); auto entity = getTree()->findEntityByEntityItemID(entityID); if (entity) { - auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; scriptEngine->callEntityScriptMethod(entityID, "enterEntity"); } } @@ -733,8 +733,8 @@ void EntityTreeRenderer::leaveDomainAndNonOwnedEntities() { EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); if (entityItem && !(entityItem->isLocalEntity() || entityItem->isMyAvatarEntity())) { emit leaveEntity(entityID); - if (_nonPersistentEntitiesScriptEngine) { - _nonPersistentEntitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); + if (_nonPersistentEntitiesScriptManager) { + _nonPersistentEntitiesScriptManager->callEntityScriptMethod(entityID, "leaveEntity"); } } else { currentEntitiesInsideToSave.insert(entityID); @@ -754,7 +754,7 @@ void EntityTreeRenderer::leaveAllEntities() { emit leaveEntity(entityID); EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); if (entityItem) { - auto& scriptEngine = (entityItem->isLocalEntity() || entityItem->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entityItem->isLocalEntity() || entityItem->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; if (scriptEngine) { scriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); } @@ -1053,7 +1053,7 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { return; } - auto& scriptEngine = (itr->second->getEntity()->isLocalEntity() || itr->second->getEntity()->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (itr->second->getEntity()->isLocalEntity() || itr->second->getEntity()->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; if (_tree && !_shuttingDown && scriptEngine && !itr->second->getEntity()->getScript().isEmpty()) { if (_currentEntitiesInside.contains(entityID)) { scriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); @@ -1103,7 +1103,7 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool if (!entity) { return; } - auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; bool shouldLoad = entity->shouldPreloadScript() && scriptEngine; QString scriptUrl = entity->getScript(); if ((shouldLoad && unloadFirst) || scriptUrl.isEmpty()) { @@ -1224,7 +1224,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons if ((myNodeID == entityASimulatorID && entityAIsDynamic) || (myNodeID == entityBSimulatorID && (!entityAIsDynamic || entityASimulatorID.isNull()))) { playEntityCollisionSound(entityA, collision); emit collisionWithEntity(idA, idB, collision); - auto& scriptEngine = (entityA->isLocalEntity() || entityA->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entityA->isLocalEntity() || entityA->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; if (scriptEngine) { scriptEngine->callEntityScriptMethod(idA, "collisionWithEntity", idB, collision); } @@ -1236,7 +1236,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons Collision invertedCollision(collision); invertedCollision.invert(); emit collisionWithEntity(idB, idA, invertedCollision); - auto& scriptEngine = (entityB->isLocalEntity() || entityB->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entityB->isLocalEntity() || entityB->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; if (scriptEngine) { scriptEngine->callEntityScriptMethod(idB, "collisionWithEntity", idA, invertedCollision); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 009e5f6c4f4..f4fdc222e8a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include // for RayToEntityIntersectionResult @@ -32,6 +33,10 @@ class Model; class ScriptEngine; class ZoneEntityItem; class EntityItem; +class ScriptEngine; +class ScriptManager; +using ScriptEnginePointer = QSharedPointer; +using ScriptManagerPointer = QSharedPointer; namespace render { namespace entities { class EntityRenderer; @@ -175,7 +180,7 @@ public slots: void resetPersistentEntitiesScriptEngine(); void resetNonPersistentEntitiesScriptEngine(); - void setupEntityScriptEngineSignals(const ScriptEnginePointer& scriptEngine); + void setupEntityScriptEngineSignals(const ScriptManagerPointer& scriptManager); void findBestZoneAndMaybeContainingEntities(QSet& entitiesContainingAvatar); @@ -187,7 +192,7 @@ public slots: EntityItemID _currentHoverOverEntityID; EntityItemID _currentClickingOnEntityID; - QScriptValueList createEntityArgs(const EntityItemID& entityID); + ScriptValueList createEntityArgs(const EntityItemID& entityID); void checkEnterLeaveEntities(); void leaveDomainAndNonOwnedEntities(); void leaveAllEntities(); @@ -198,8 +203,8 @@ public slots: QSet _currentEntitiesInside; bool _wantScripts; - ScriptEnginePointer _nonPersistentEntitiesScriptEngine; // used for domain + non-owned avatar entities, cleared on domain switch - ScriptEnginePointer _persistentEntitiesScriptEngine; // used for local + owned avatar entities, persists on domain switch, cleared on reload content + ScriptManagerPointer _nonPersistentEntitiesScriptManager; // used for domain + non-owned avatar entities, cleared on domain switch + ScriptManagerPointer _persistentEntitiesScriptManager; // used for local + owned avatar entities, persists on domain switch, cleared on reload content void playEntityCollisionSound(const EntityItemPointer& entity, const Collision& collision); diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index bddd4b5e67d..9214023af56 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME entities) -setup_hifi_library(Network Script) +setup_hifi_library(Network) target_include_directories(${TARGET_NAME} PRIVATE "${OPENSSL_INCLUDE_DIR}") +include_hifi_library_headers(animation) include_hifi_library_headers(hfm) include_hifi_library_headers(model-serializers) include_hifi_library_headers(gpu) @@ -8,4 +9,4 @@ include_hifi_library_headers(image) include_hifi_library_headers(ktx) include_hifi_library_headers(material-networking) include_hifi_library_headers(procedural) -link_hifi_libraries(shared shaders networking octree avatars graphics model-networking) +link_hifi_libraries(shared shaders networking octree avatars graphics model-networking script-engine) diff --git a/libraries/entities/src/AmbientLightPropertyGroup.cpp b/libraries/entities/src/AmbientLightPropertyGroup.cpp index 38017a684b1..19585943733 100644 --- a/libraries/entities/src/AmbientLightPropertyGroup.cpp +++ b/libraries/entities/src/AmbientLightPropertyGroup.cpp @@ -19,14 +19,14 @@ const float AmbientLightPropertyGroup::DEFAULT_AMBIENT_LIGHT_INTENSITY = 0.5f; -void AmbientLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void AmbientLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_LIGHT_INTENSITY, AmbientLight, ambientLight, AmbientIntensity, ambientIntensity); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_LIGHT_URL, AmbientLight, ambientLight, AmbientURL, ambientURL); } -void AmbientLightPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void AmbientLightPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientLight, ambientIntensity, float, setAmbientIntensity); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientLight, ambientURL, QString, setAmbientURL); diff --git a/libraries/entities/src/AmbientLightPropertyGroup.h b/libraries/entities/src/AmbientLightPropertyGroup.h index d1e0ea0e551..7a9296450d5 100644 --- a/libraries/entities/src/AmbientLightPropertyGroup.h +++ b/libraries/entities/src/AmbientLightPropertyGroup.h @@ -17,7 +17,7 @@ #include -#include +#include #include "EntityItemPropertiesMacros.h" #include "PropertyGroup.h" @@ -26,6 +26,9 @@ class EncodeBitstreamParams; class OctreePacketData; class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * Ambient light is defined by the following properties: @@ -38,10 +41,10 @@ class ReadBitstreamToTreeParams; class AmbientLightPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const AmbientLightPropertyGroup& other); diff --git a/libraries/entities/src/AnimationPropertyGroup.cpp b/libraries/entities/src/AnimationPropertyGroup.cpp index 38230b4f50d..32c5478413a 100644 --- a/libraries/entities/src/AnimationPropertyGroup.cpp +++ b/libraries/entities/src/AnimationPropertyGroup.cpp @@ -65,7 +65,7 @@ bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b * @property {boolean} hold=false - true if the rotations and translations of the last frame played are * maintained when the animation stops playing, false if they aren't. */ -void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps); @@ -78,7 +78,7 @@ void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire } -void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void AnimationPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, url, QString, setURL); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, allowTranslation, bool, setAllowTranslation); diff --git a/libraries/entities/src/AnimationPropertyGroup.h b/libraries/entities/src/AnimationPropertyGroup.h index bebfe2c1946..baa27b96136 100644 --- a/libraries/entities/src/AnimationPropertyGroup.h +++ b/libraries/entities/src/AnimationPropertyGroup.h @@ -17,8 +17,7 @@ #include -#include - +#include #include "EntityItemPropertiesMacros.h" #include "PropertyGroup.h" @@ -27,16 +26,19 @@ class EncodeBitstreamParams; class OctreePacketData; class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class AnimationPropertyGroup : public PropertyGroup { public: static const float MAXIMUM_POSSIBLE_FRAME; // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const AnimationPropertyGroup& other); diff --git a/libraries/entities/src/BloomPropertyGroup.cpp b/libraries/entities/src/BloomPropertyGroup.cpp index 2c4d46ab35f..672b3e9623a 100644 --- a/libraries/entities/src/BloomPropertyGroup.cpp +++ b/libraries/entities/src/BloomPropertyGroup.cpp @@ -16,13 +16,13 @@ #include "EntityItemProperties.h" #include "EntityItemPropertiesMacros.h" -void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize); } -void BloomPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void BloomPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomIntensity, float, setBloomIntensity); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomThreshold, float, setBloomThreshold); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomSize, float, setBloomSize); diff --git a/libraries/entities/src/BloomPropertyGroup.h b/libraries/entities/src/BloomPropertyGroup.h index 12743c9298d..82ab986275c 100644 --- a/libraries/entities/src/BloomPropertyGroup.h +++ b/libraries/entities/src/BloomPropertyGroup.h @@ -15,7 +15,7 @@ #include #include -#include +#include #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" @@ -25,6 +25,9 @@ class EncodeBitstreamParams; class OctreePacketData; class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; static const float INITIAL_BLOOM_INTENSITY { 0.25f }; static const float INITIAL_BLOOM_THRESHOLD { 0.7f }; @@ -40,10 +43,10 @@ static const float INITIAL_BLOOM_SIZE { 0.9f }; class BloomPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const BloomPropertyGroup& other); diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 16dace0fc8f..6d2280f0bfb 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -15,6 +15,9 @@ #include #include +#include +#include +#include QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { QList zones; @@ -76,19 +79,19 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper auto oldProperties = propertiesIn.getDesiredProperties(); auto specifiedProperties = propertiesIn.getChangedProperties(); propertiesIn.setDesiredProperties(specifiedProperties); - QScriptValue inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true); + ScriptValuePointer inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true); propertiesIn.setDesiredProperties(oldProperties); - auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. + auto in = QJsonValue::fromVariant(inputValues->toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. - QScriptValueList args; + ScriptValueList args; args << inputValues; - args << filterType; + args << filterData.engine->newValue(filterType); // get the current properties for then entity and include them for the filter call if (existingEntity && filterData.wantsOriginalProperties) { auto currentProperties = existingEntity->getProperties(filterData.includedOriginalProperties); - QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); + ScriptValuePointer currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); args << currentValues; } @@ -98,22 +101,22 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper auto zoneEntity = _tree->findEntityByEntityItemID(id); if (zoneEntity) { auto zoneProperties = zoneEntity->getProperties(filterData.includedZoneProperties); - QScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); + ScriptValuePointer zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); if (filterData.wantsZoneBoundingBox) { bool success = true; AABox aaBox = zoneEntity->getAABox(success); if (success) { - QScriptValue boundingBox = filterData.engine->newObject(); - QScriptValue bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner()); - QScriptValue topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft()); - QScriptValue center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter()); - QScriptValue boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions()); - boundingBox.setProperty("brn", bottomRightNear); - boundingBox.setProperty("tfl", topFarLeft); - boundingBox.setProperty("center", center); - boundingBox.setProperty("dimensions", boundingBoxDimensions); - zoneValues.setProperty("boundingBox", boundingBox); + ScriptValuePointer boundingBox = filterData.engine->newObject(); + ScriptValuePointer bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner()); + ScriptValuePointer topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft()); + ScriptValuePointer center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter()); + ScriptValuePointer boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions()); + boundingBox->setProperty("brn", bottomRightNear); + boundingBox->setProperty("tfl", topFarLeft); + boundingBox->setProperty("center", center); + boundingBox->setProperty("dimensions", boundingBoxDimensions); + zoneValues->setProperty("boundingBox", boundingBox); } } @@ -122,32 +125,32 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper // to be the fourth parameter, so we need to pad the args accordingly int EXPECTED_ARGS = 3; if (args.length() < EXPECTED_ARGS) { - args << QScriptValue(); + args << ScriptValuePointer(); } assert(args.length() == EXPECTED_ARGS); // we MUST have 3 args by now! args << zoneValues; } } - QScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args); + ScriptValuePointer result = filterData.filterFn->call(_nullObjectForFilter, args); if (filterData.uncaughtExceptions()) { return false; } - if (result.isObject()) { + if (result->isObject()) { // make propertiesIn reflect the changes, for next filter... propertiesIn.copyFromScriptValue(result, false); // and update propertiesOut too. TODO: this could be more efficient... propertiesOut.copyFromScriptValue(result, false); // Javascript objects are == only if they are the same object. To compare arbitrary values, we need to use JSON. - auto out = QJsonValue::fromVariant(result.toVariant()); + auto out = QJsonValue::fromVariant(result->toVariant()); wasChanged |= (in != out); - } else if (result.isBool()) { + } else if (result->isBool()) { // if the filter returned false, then it's authoritative - if (!result.toBool()) { + if (!result->toBool()) { return false; } @@ -216,23 +219,23 @@ void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) { } // Copied from ScriptEngine.cpp. We should make this a class method for reuse. -// Note: I've deliberately stopped short of using ScriptEngine instead of QScriptEngine, as that is out of project scope at this point. -static bool hasCorrectSyntax(const QScriptProgram& program) { - const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); - if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { - const auto error = syntaxCheck.errorMessage(); - const auto line = QString::number(syntaxCheck.errorLineNumber()); - const auto column = QString::number(syntaxCheck.errorColumnNumber()); - const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column); +// Note: I've deliberately stopped short of using ScriptEngine instead of ScriptEngine, as that is out of project scope at this point. +static bool hasCorrectSyntax(const ScriptProgramPointer& program) { + const auto syntaxCheck = program->checkSyntax(); + if (syntaxCheck->state() != ScriptSyntaxCheckResult::Valid) { + const auto error = syntaxCheck->errorMessage(); + const auto line = QString::number(syntaxCheck->errorLineNumber()); + const auto column = QString::number(syntaxCheck->errorColumnNumber()); + const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program->fileName(), line, column); qCritical() << qPrintable(message); return false; } return true; } -static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) { +static bool hadUncaughtExceptions(ScriptEngine& engine, const QString& fileName) { if (engine.hasUncaughtException()) { const auto backtrace = engine.uncaughtExceptionBacktrace(); - const auto exception = engine.uncaughtException().toString(); + const auto exception = engine.uncaughtException()->toString(); const auto line = QString::number(engine.uncaughtExceptionLineNumber()); engine.clearExceptions(); @@ -255,92 +258,93 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { const QString urlString = scriptRequest->getUrl().toString(); auto scriptContents = scriptRequest->getData(); qInfo() << "Downloaded script:" << scriptContents; - QScriptProgram program(scriptContents, urlString); + // create a ScriptEngine for this script + ScriptManagerPointer manager = newScriptManager(ScriptManager::ENTITY_SERVER_SCRIPT, "", urlString); + ScriptEnginePointer engine = manager->engine(); + ScriptProgramPointer program = engine->newProgram(scriptContents, urlString); if (hasCorrectSyntax(program)) { - // create a QScriptEngine for this script - QScriptEngine* engine = new QScriptEngine(); engine->setObjectName("filter:" + entityID.toString()); engine->setProperty("type", "edit_filter"); engine->setProperty("fileName", urlString); engine->setProperty("entityID", entityID); - engine->globalObject().setProperty("Script", engine->newQObject(engine)); - DependencyManager::get()->runScriptInitializers(engine); + engine->globalObject()->setProperty("Script", engine->newQObject(manager.get())); + DependencyManager::get()->runScriptInitializers(engine.data()); engine->evaluate(scriptContents, urlString); if (!hadUncaughtExceptions(*engine, urlString)) { // put the engine in the engine map (so we don't leak them, etc...) FilterData filterData; - filterData.engine = engine; + filterData.engine = engine.get(); filterData.rejectAll = false; // define the uncaughtException function - QScriptEngine& engineRef = *engine; + ScriptEngine& engineRef = *engine; filterData.uncaughtExceptions = [&engineRef, urlString]() { return hadUncaughtExceptions(engineRef, urlString); }; // now get the filter function auto global = engine->globalObject(); auto entitiesObject = engine->newObject(); - entitiesObject.setProperty("ADD_FILTER_TYPE", EntityTree::FilterType::Add); - entitiesObject.setProperty("EDIT_FILTER_TYPE", EntityTree::FilterType::Edit); - entitiesObject.setProperty("PHYSICS_FILTER_TYPE", EntityTree::FilterType::Physics); - entitiesObject.setProperty("DELETE_FILTER_TYPE", EntityTree::FilterType::Delete); - global.setProperty("Entities", entitiesObject); - filterData.filterFn = global.property("filter"); - if (!filterData.filterFn.isFunction()) { + entitiesObject->setProperty("ADD_FILTER_TYPE", EntityTree::FilterType::Add); + entitiesObject->setProperty("EDIT_FILTER_TYPE", EntityTree::FilterType::Edit); + entitiesObject->setProperty("PHYSICS_FILTER_TYPE", EntityTree::FilterType::Physics); + entitiesObject->setProperty("DELETE_FILTER_TYPE", EntityTree::FilterType::Delete); + global->setProperty("Entities", entitiesObject); + filterData.filterFn = global->property("filter"); + if (!filterData.filterFn->isFunction()) { qDebug() << "Filter function specified but not found. Will reject all edits for those without lock rights."; - delete engine; + engine.reset(); filterData.rejectAll=true; } // if the wantsToFilterEdit is a boolean evaluate as a boolean, otherwise assume true - QScriptValue wantsToFilterAddValue = filterData.filterFn.property("wantsToFilterAdd"); - filterData.wantsToFilterAdd = wantsToFilterAddValue.isBool() ? wantsToFilterAddValue.toBool() : true; + ScriptValuePointer wantsToFilterAddValue = filterData.filterFn->property("wantsToFilterAdd"); + filterData.wantsToFilterAdd = wantsToFilterAddValue->isBool() ? wantsToFilterAddValue->toBool() : true; // if the wantsToFilterEdit is a boolean evaluate as a boolean, otherwise assume true - QScriptValue wantsToFilterEditValue = filterData.filterFn.property("wantsToFilterEdit"); - filterData.wantsToFilterEdit = wantsToFilterEditValue.isBool() ? wantsToFilterEditValue.toBool() : true; + ScriptValuePointer wantsToFilterEditValue = filterData.filterFn->property("wantsToFilterEdit"); + filterData.wantsToFilterEdit = wantsToFilterEditValue->isBool() ? wantsToFilterEditValue->toBool() : true; // if the wantsToFilterPhysics is a boolean evaluate as a boolean, otherwise assume true - QScriptValue wantsToFilterPhysicsValue = filterData.filterFn.property("wantsToFilterPhysics"); - filterData.wantsToFilterPhysics = wantsToFilterPhysicsValue.isBool() ? wantsToFilterPhysicsValue.toBool() : true; + ScriptValuePointer wantsToFilterPhysicsValue = filterData.filterFn->property("wantsToFilterPhysics"); + filterData.wantsToFilterPhysics = wantsToFilterPhysicsValue->isBool() ? wantsToFilterPhysicsValue->toBool() : true; // if the wantsToFilterDelete is a boolean evaluate as a boolean, otherwise assume false - QScriptValue wantsToFilterDeleteValue = filterData.filterFn.property("wantsToFilterDelete"); - filterData.wantsToFilterDelete = wantsToFilterDeleteValue.isBool() ? wantsToFilterDeleteValue.toBool() : false; + ScriptValuePointer wantsToFilterDeleteValue = filterData.filterFn->property("wantsToFilterDelete"); + filterData.wantsToFilterDelete = wantsToFilterDeleteValue->isBool() ? wantsToFilterDeleteValue->toBool() : false; // check to see if the filterFn has properties asking for Original props - QScriptValue wantsOriginalPropertiesValue = filterData.filterFn.property("wantsOriginalProperties"); + ScriptValuePointer wantsOriginalPropertiesValue = filterData.filterFn->property("wantsOriginalProperties"); // if the wantsOriginalProperties is a boolean, or a string, or list of strings, then evaluate as follows: // - boolean - true - include all original properties // false - no properties at all // - string - empty - no properties at all // any valid property - include just that property in the Original properties // - list of strings - include only those properties in the Original properties - if (wantsOriginalPropertiesValue.isBool()) { - filterData.wantsOriginalProperties = wantsOriginalPropertiesValue.toBool(); - } else if (wantsOriginalPropertiesValue.isString()) { - auto stringValue = wantsOriginalPropertiesValue.toString(); + if (wantsOriginalPropertiesValue->isBool()) { + filterData.wantsOriginalProperties = wantsOriginalPropertiesValue->toBool(); + } else if (wantsOriginalPropertiesValue->isString()) { + auto stringValue = wantsOriginalPropertiesValue->toString(); filterData.wantsOriginalProperties = !stringValue.isEmpty(); if (filterData.wantsOriginalProperties) { EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); } - } else if (wantsOriginalPropertiesValue.isArray()) { + } else if (wantsOriginalPropertiesValue->isArray()) { EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); filterData.wantsOriginalProperties = !filterData.includedOriginalProperties.isEmpty(); } // check to see if the filterFn has properties asking for Zone props - QScriptValue wantsZonePropertiesValue = filterData.filterFn.property("wantsZoneProperties"); + ScriptValuePointer wantsZonePropertiesValue = filterData.filterFn->property("wantsZoneProperties"); // if the wantsZoneProperties is a boolean, or a string, or list of strings, then evaluate as follows: // - boolean - true - include all Zone properties // false - no properties at all // - string - empty - no properties at all // any valid property - include just that property in the Zone properties // - list of strings - include only those properties in the Zone properties - if (wantsZonePropertiesValue.isBool()) { - filterData.wantsZoneProperties = wantsZonePropertiesValue.toBool(); + if (wantsZonePropertiesValue->isBool()) { + filterData.wantsZoneProperties = wantsZonePropertiesValue->toBool(); filterData.wantsZoneBoundingBox = filterData.wantsZoneProperties; // include this too - } else if (wantsZonePropertiesValue.isString()) { - auto stringValue = wantsZonePropertiesValue.toString(); + } else if (wantsZonePropertiesValue->isString()) { + auto stringValue = wantsZonePropertiesValue->toString(); filterData.wantsZoneProperties = !stringValue.isEmpty(); if (filterData.wantsZoneProperties) { if (stringValue == "boundingBox") { @@ -349,10 +353,10 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { EntityPropertyFlagsFromScriptValue(wantsZonePropertiesValue, filterData.includedZoneProperties); } } - } else if (wantsZonePropertiesValue.isArray()) { - auto length = wantsZonePropertiesValue.property("length").toInteger(); + } else if (wantsZonePropertiesValue->isArray()) { + auto length = wantsZonePropertiesValue->property("length")->toInteger(); for (int i = 0; i < length; i++) { - auto stringValue = wantsZonePropertiesValue.property(i).toString(); + auto stringValue = wantsZonePropertiesValue->property(i)->toString(); if (!stringValue.isEmpty()) { filterData.wantsZoneProperties = true; diff --git a/libraries/entities/src/EntityEditFilters.h b/libraries/entities/src/EntityEditFilters.h index d1cef0c5f09..26dd91cc68b 100644 --- a/libraries/entities/src/EntityEditFilters.h +++ b/libraries/entities/src/EntityEditFilters.h @@ -13,21 +13,24 @@ #include #include -#include -#include +#include #include #include +#include + #include "EntityItemID.h" #include "EntityItemProperties.h" #include "EntityTree.h" +class ScriptEngine; + class EntityEditFilters : public QObject, public Dependency { Q_OBJECT public: struct FilterData { - QScriptValue filterFn; + ScriptValuePointer filterFn; bool wantsOriginalProperties { false }; bool wantsZoneProperties { false }; @@ -41,11 +44,11 @@ class EntityEditFilters : public QObject, public Dependency { bool wantsZoneBoundingBox { false }; std::function uncaughtExceptions; - QScriptEngine* engine; + ScriptEngine* engine; bool rejectAll; FilterData(): engine(nullptr), rejectAll(false) {}; - bool valid() { return (rejectAll || (engine != nullptr && filterFn.isFunction() && uncaughtExceptions)); } + bool valid() { return (rejectAll || (engine != nullptr && filterFn->isFunction() && uncaughtExceptions)); } }; EntityEditFilters() {}; @@ -68,7 +71,7 @@ private slots: EntityTreePointer _tree {}; bool _rejectAll {false}; - QScriptValue _nullObjectForFilter{}; + ScriptValuePointer _nullObjectForFilter{}; QReadWriteLock _lock; QMap _filterDataMap; diff --git a/libraries/entities/src/EntityItemID.cpp b/libraries/entities/src/EntityItemID.cpp index 28b8e109ca1..874a0fcd531 100644 --- a/libraries/entities/src/EntityItemID.cpp +++ b/libraries/entities/src/EntityItemID.cpp @@ -18,6 +18,8 @@ #include #include "RegisteredMetaTypes.h" +#include +#include int entityItemIDTypeID = qRegisterMetaType(); @@ -42,27 +44,27 @@ EntityItemID EntityItemID::readEntityItemIDFromBuffer(const unsigned char* data, return result; } -QScriptValue EntityItemID::toScriptValue(QScriptEngine* engine) const { +ScriptValuePointer EntityItemID::toScriptValue(ScriptEngine* engine) const { return EntityItemIDtoScriptValue(engine, *this); } -QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& id) { +ScriptValuePointer EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& id) { return quuidToScriptValue(engine, id); } -void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) { +void EntityItemIDfromScriptValue(const ScriptValuePointer &object, EntityItemID& id) { quuidFromScriptValue(object, id); } -QVector qVectorEntityItemIDFromScriptValue(const QScriptValue& array) { - if (!array.isArray()) { +QVector qVectorEntityItemIDFromScriptValue(const ScriptValuePointer& array) { + if (!array->isArray()) { return QVector(); } QVector newVector; - int length = array.property("length").toInteger(); + int length = array->property("length")->toInteger(); newVector.reserve(length); for (int i = 0; i < length; i++) { - QString uuidAsString = array.property(i).toString(); + QString uuidAsString = array->property(i)->toString(); EntityItemID fromString(uuidAsString); newVector << fromString; } diff --git a/libraries/entities/src/EntityItemID.h b/libraries/entities/src/EntityItemID.h index 5ff58ede362..499493fa10f 100644 --- a/libraries/entities/src/EntityItemID.h +++ b/libraries/entities/src/EntityItemID.h @@ -17,9 +17,13 @@ #include #include #include -#include +#include #include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + const QUuid UNKNOWN_ENTITY_ID; // null uuid /// Abstract ID for editing model items. Used in EntityItem JS API. @@ -29,7 +33,7 @@ class EntityItemID : public QUuid { EntityItemID(const QUuid& id); // EntityItemID(const EntityItemID& other); static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead); - QScriptValue toScriptValue(QScriptEngine* engine) const; + ScriptValuePointer toScriptValue(ScriptEngine* engine) const; bool isInvalidID() const { return *this == UNKNOWN_ENTITY_ID; } }; @@ -41,9 +45,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemID& id) { Q_DECLARE_METATYPE(EntityItemID); Q_DECLARE_METATYPE(QVector); -QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& properties); -void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& properties); -QVector qVectorEntityItemIDFromScriptValue(const QScriptValue& array); +ScriptValuePointer EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& properties); +void EntityItemIDfromScriptValue(const ScriptValuePointer &object, EntityItemID& properties); +QVector qVectorEntityItemIDFromScriptValue(const ScriptValuePointer& array); // Allow the use of std::unordered_map with QUuid keys namespace std { template<> struct hash { size_t operator()(const EntityItemID& id) const; }; } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 524c6316317..d58f70e12a8 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "EntitiesLogging.h" #include "EntityItem.h" @@ -1569,14 +1570,14 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {Entities.RingGizmo} ring - The ring gizmo properties. */ -QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, +ScriptValuePointer EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, bool strictSemantics, EntityPsuedoPropertyFlags psueudoPropertyFlags) const { // If strictSemantics is true and skipDefaults is false, then all and only those properties are copied for which the property flag // is included in _desiredProperties, or is one of the specially enumerated ALWAYS properties below. // (There may be exceptions, but if so, they are bugs.) // In all other cases, you are welcome to inspect the code and try to figure out what was intended. I wish you luck. -HRS 1/18/17 - QScriptValue properties = engine->newObject(); + ScriptValuePointer properties = engine->newObject(); EntityItemProperties defaultEntityProperties; const bool psuedoPropertyFlagsActive = psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::FlagsActive); @@ -1603,7 +1604,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool } } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::LastEdited)) { - properties.setProperty("lastEdited", convertScriptValue(engine, _lastEdited)); + properties->setProperty("lastEdited", convertScriptValue(engine, _lastEdited)); } if (!skipDefaults) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, naturalDimensions); // gettable, but not settable @@ -1920,9 +1921,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool // Handle conversions to old 'textures' property from "imageURL" if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(PROP_IMAGE_URL)) && (!skipDefaults || defaultEntityProperties._imageURL != _imageURL)) { - QScriptValue textures = engine->newObject(); - textures.setProperty("tex.picture", _imageURL); - properties.setProperty("textures", textures); + ScriptValuePointer textures = engine->newObject(); + textures->setProperty("tex.picture", _imageURL); + properties->setProperty("textures", textures); } } @@ -1955,15 +1956,15 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::BoundingBox))) { AABox aaBox = getAABox(); - QScriptValue boundingBox = engine->newObject(); - QScriptValue bottomRightNear = vec3ToScriptValue(engine, aaBox.getCorner()); - QScriptValue topFarLeft = vec3ToScriptValue(engine, aaBox.calcTopFarLeft()); - QScriptValue center = vec3ToScriptValue(engine, aaBox.calcCenter()); - QScriptValue boundingBoxDimensions = vec3ToScriptValue(engine, aaBox.getDimensions()); - boundingBox.setProperty("brn", bottomRightNear); - boundingBox.setProperty("tfl", topFarLeft); - boundingBox.setProperty("center", center); - boundingBox.setProperty("dimensions", boundingBoxDimensions); + ScriptValuePointer boundingBox = engine->newObject(); + ScriptValuePointer bottomRightNear = vec3ToScriptValue(engine, aaBox.getCorner()); + ScriptValuePointer topFarLeft = vec3ToScriptValue(engine, aaBox.calcTopFarLeft()); + ScriptValuePointer center = vec3ToScriptValue(engine, aaBox.calcCenter()); + ScriptValuePointer boundingBoxDimensions = vec3ToScriptValue(engine, aaBox.getDimensions()); + boundingBox->setProperty("brn", bottomRightNear); + boundingBox->setProperty("tfl", topFarLeft); + boundingBox->setProperty("center", center); + boundingBox->setProperty("dimensions", boundingBoxDimensions); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable } @@ -1976,7 +1977,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool if (!skipDefaults && !strictSemantics && (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::RenderInfo))) { - QScriptValue renderInfo = engine->newObject(); + ScriptValuePointer renderInfo = engine->newObject(); /**jsdoc * Information on how an entity is rendered. Properties are only filled in for Model entities; other @@ -1991,40 +1992,40 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool */ // currently only supported by models if (_type == EntityTypes::Model) { - renderInfo.setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int - renderInfo.setProperty("texturesSize", (int)getRenderInfoTextureSize()); // FIXME - theoretically the size of textures could be > max int - renderInfo.setProperty("hasTransparent", getRenderInfoHasTransparent()); - renderInfo.setProperty("drawCalls", getRenderInfoDrawCalls()); - renderInfo.setProperty("texturesCount", getRenderInfoTextureCount()); + renderInfo->setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int + renderInfo->setProperty("texturesSize", (int)getRenderInfoTextureSize()); // FIXME - theoretically the size of textures could be > max int + renderInfo->setProperty("hasTransparent", getRenderInfoHasTransparent()); + renderInfo->setProperty("drawCalls", getRenderInfoDrawCalls()); + renderInfo->setProperty("texturesCount", getRenderInfoTextureCount()); } COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::ClientOnly)) { - properties.setProperty("clientOnly", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); + properties->setProperty("clientOnly", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::AvatarEntity)) { - properties.setProperty("avatarEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); + properties->setProperty("avatarEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::LocalEntity)) { - properties.setProperty("localEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::LOCAL)); + properties->setProperty("localEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::LOCAL)); } if (_type != EntityTypes::PolyLine && (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::FaceCamera))) { - properties.setProperty("faceCamera", convertScriptValue(engine, getBillboardMode() == BillboardMode::YAW)); + properties->setProperty("faceCamera", convertScriptValue(engine, getBillboardMode() == BillboardMode::YAW)); } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::IsFacingAvatar)) { - properties.setProperty("isFacingAvatar", convertScriptValue(engine, getBillboardMode() == BillboardMode::FULL)); + properties->setProperty("isFacingAvatar", convertScriptValue(engine, getBillboardMode() == BillboardMode::FULL)); } return properties; } -void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool honorReadOnly) { - QScriptValue typeScriptValue = object.property("type"); - if (typeScriptValue.isValid()) { - setType(typeScriptValue.toVariant().toString()); +void EntityItemProperties::copyFromScriptValue(const ScriptValuePointer& object, bool honorReadOnly) { + ScriptValuePointer typeScriptValue = object->property("type"); + if (typeScriptValue->isValid()) { + setType(typeScriptValue->toVariant().toString()); } // Core @@ -2277,8 +2278,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool // Handle conversions from old 'textures' property to "imageURL" { - QScriptValue V = object.property("textures"); - if (_type == EntityTypes::Image && V.isValid() && !object.property("imageURL").isValid()) { + ScriptValuePointer V = object->property("textures"); + if (_type == EntityTypes::Image && V->isValid() && !object->property("imageURL")->isValid()) { bool isValid = false; QString textures = QString_convertFromScriptValue(V, isValid); if (isValid) { @@ -2296,9 +2297,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool // Handle old "faceCamera" and "isFacingAvatar" props if (_type != EntityTypes::PolyLine) { - QScriptValue P = object.property("faceCamera"); - if (P.isValid() && !object.property("billboardMode").isValid()) { - bool newValue = P.toVariant().toBool(); + ScriptValuePointer P = object->property("faceCamera"); + if (P->isValid() && !object->property("billboardMode")->isValid()) { + bool newValue = P->toVariant().toBool(); bool oldValue = getBillboardMode() == BillboardMode::YAW; if (_defaultSettings || newValue != oldValue) { setBillboardMode(newValue ? BillboardMode::YAW : BillboardMode::NONE); @@ -2306,9 +2307,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool } } { - QScriptValue P = object.property("isFacingAvatar"); - if (P.isValid() && !object.property("billboardMode").isValid() && !object.property("faceCamera").isValid()) { - bool newValue = P.toVariant().toBool(); + ScriptValuePointer P = object->property("isFacingAvatar"); + if (P->isValid() && !object->property("billboardMode")->isValid() && !object->property("faceCamera")->isValid()) { + bool newValue = P->toVariant().toBool(); bool oldValue = getBillboardMode() == BillboardMode::FULL; if (_defaultSettings || newValue != oldValue) { setBillboardMode(newValue ? BillboardMode::FULL : BillboardMode::NONE); @@ -2319,13 +2320,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool _lastEdited = usecTimestampNow(); } -void EntityItemProperties::copyFromJSONString(QScriptEngine& scriptEngine, const QString& jsonString) { +void EntityItemProperties::copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString) { // DANGER: this method is expensive QJsonDocument propertiesDoc = QJsonDocument::fromJson(jsonString.toUtf8()); QJsonObject propertiesObj = propertiesDoc.object(); QVariant propertiesVariant(propertiesObj); QVariantMap propertiesMap = propertiesVariant.toMap(); - QScriptValue propertiesScriptValue = variantMapToScriptValue(propertiesMap, scriptEngine); + ScriptValuePointer propertiesScriptValue = variantMapToScriptValue(propertiesMap, scriptEngine); bool honorReadOnly = true; copyFromScriptValue(propertiesScriptValue, honorReadOnly); } @@ -2573,47 +2574,47 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { _lastEdited = usecTimestampNow(); } -QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties) { +ScriptValuePointer EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { return properties.copyToScriptValue(engine, false); } -QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties) { +ScriptValuePointer EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { return properties.copyToScriptValue(engine, true); } -void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties) { +void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValuePointer &object, EntityItemProperties& properties) { properties.copyFromScriptValue(object, false); } -void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties) { +void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValuePointer &object, EntityItemProperties& properties) { properties.copyFromScriptValue(object, true); } -QScriptValue EntityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags) { +ScriptValuePointer EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { return EntityItemProperties::entityPropertyFlagsToScriptValue(engine, flags); } -void EntityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags) { +void EntityPropertyFlagsFromScriptValue(const ScriptValuePointer& object, EntityPropertyFlags& flags) { EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags); } -QScriptValue EntityItemProperties::entityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags) { - QScriptValue result = engine->newObject(); +ScriptValuePointer EntityItemProperties::entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { + ScriptValuePointer result = engine->newObject(); return result; } -void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags) { - if (object.isString()) { +void EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValuePointer& object, EntityPropertyFlags& flags) { + if (object->isString()) { EntityPropertyInfo propertyInfo; - if (getPropertyInfo(object.toString(), propertyInfo)) { + if (getPropertyInfo(object->toString(), propertyInfo)) { flags << propertyInfo.propertyEnum; } } - else if (object.isArray()) { - quint32 length = object.property("length").toInt32(); + else if (object->isArray()) { + quint32 length = object->property("length")->toInt32(); for (quint32 i = 0; i < length; i++) { - QString propertyName = object.property(i).toString(); + QString propertyName = object->property(i)->toString(); EntityPropertyInfo propertyInfo; if (getPropertyInfo(propertyName, propertyInfo)) { flags << propertyInfo.propertyEnum; @@ -3012,18 +3013,18 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr * @property {string} minimum - The minimum numerical value the property may have, if available, otherwise "". * @property {string} maximum - The maximum numerical value the property may have, if available, otherwise "". */ -QScriptValue EntityPropertyInfoToScriptValue(QScriptEngine* engine, const EntityPropertyInfo& propertyInfo) { - QScriptValue obj = engine->newObject(); - obj.setProperty("propertyEnum", propertyInfo.propertyEnum); - obj.setProperty("minimum", propertyInfo.minimum.toString()); - obj.setProperty("maximum", propertyInfo.maximum.toString()); +ScriptValuePointer EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("propertyEnum", propertyInfo.propertyEnum); + obj->setProperty("minimum", propertyInfo.minimum.toString()); + obj->setProperty("maximum", propertyInfo.maximum.toString()); return obj; } -void EntityPropertyInfoFromScriptValue(const QScriptValue& object, EntityPropertyInfo& propertyInfo) { - propertyInfo.propertyEnum = (EntityPropertyList)object.property("propertyEnum").toVariant().toUInt(); - propertyInfo.minimum = object.property("minimum").toVariant(); - propertyInfo.maximum = object.property("maximum").toVariant(); +void EntityPropertyInfoFromScriptValue(const ScriptValuePointer& object, EntityPropertyInfo& propertyInfo) { + propertyInfo.propertyEnum = (EntityPropertyList)object->property("propertyEnum")->toVariant().toUInt(); + propertyInfo.minimum = object->property("minimum")->toVariant(); + propertyInfo.maximum = object->property("maximum")->toVariant(); } // TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the @@ -5197,7 +5198,7 @@ void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityID setCloneAvatarEntity(ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); } -bool EntityItemProperties::blobToProperties(QScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties) { +bool EntityItemProperties::blobToProperties(ScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties) { // DANGER: this method is NOT efficient. // begin recipe for converting unfortunately-formatted-binary-blob to EntityItemProperties QJsonDocument jsonProperties = QJsonDocument::fromBinaryData(blob); @@ -5207,20 +5208,20 @@ bool EntityItemProperties::blobToProperties(QScriptEngine& scriptEngine, const Q } QVariant variant = jsonProperties.toVariant(); QVariantMap variantMap = variant.toMap(); - QScriptValue scriptValue = variantMapToScriptValue(variantMap, scriptEngine); + ScriptValuePointer scriptValue = variantMapToScriptValue(variantMap, scriptEngine); EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptValue, properties); // end recipe return true; } -void EntityItemProperties::propertiesToBlob(QScriptEngine& scriptEngine, const QUuid& myAvatarID, +void EntityItemProperties::propertiesToBlob(ScriptEngine& scriptEngine, const QUuid& myAvatarID, const EntityItemProperties& properties, QByteArray& blob, bool allProperties) { // DANGER: this method is NOT efficient. // begin recipe for extracting unfortunately-formatted-binary-blob from EntityItem - QScriptValue scriptValue = allProperties + ScriptValuePointer scriptValue = allProperties ? EntityItemPropertiesToScriptValue(&scriptEngine, properties) : EntityItemNonDefaultPropertiesToScriptValue(&scriptEngine, properties); - QVariant variantProperties = scriptValue.toVariant(); + QVariant variantProperties = scriptValue->toVariant(); QJsonDocument jsonProperties = QJsonDocument::fromVariant(variantProperties); // the ID of the parent/avatar changes from session to session. use a special UUID to indicate the avatar QJsonObject jsonObject = jsonProperties.object(); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 91de5400627..4184880ad12 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -21,11 +21,11 @@ #include #include -#include #include #include #include #include +#include #include #include @@ -69,6 +69,10 @@ #include "TextEffect.h" #include "TextAlignment.h" +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + const quint64 UNKNOWN_CREATED_TIME = 0; using vec3Color = glm::vec3; @@ -96,7 +100,7 @@ EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_i } /// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an -/// entity and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete +/// entity and a JavaScript style hash/ScriptValuePointer storing a set of properties. Used in scripting to set/get the complete /// set of entity item properties via JavaScript hashes/QScriptValues /// all units for SI units (meter, second, radian, etc) class EntityItemProperties { @@ -119,8 +123,8 @@ class EntityItemProperties { friend class ZoneEntityItem; friend class MaterialEntityItem; public: - static bool blobToProperties(QScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties); - static void propertiesToBlob(QScriptEngine& scriptEngine, const QUuid& myAvatarID, const EntityItemProperties& properties, + static bool blobToProperties(ScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties); + static void propertiesToBlob(ScriptEngine& scriptEngine, const QUuid& myAvatarID, const EntityItemProperties& properties, QByteArray& blob, bool allProperties = false); EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); @@ -133,13 +137,13 @@ class EntityItemProperties { EntityTypes::EntityType getType() const { return _type; } void setType(EntityTypes::EntityType type) { _type = type; } - virtual QScriptValue copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime = false, + virtual ScriptValuePointer copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime = false, bool strictSemantics = false, EntityPsuedoPropertyFlags psueudoPropertyFlags = EntityPsuedoPropertyFlags()) const; - virtual void copyFromScriptValue(const QScriptValue& object, bool honorReadOnly); - void copyFromJSONString(QScriptEngine& scriptEngine, const QString& jsonString); + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool honorReadOnly); + void copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString); - static QScriptValue entityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags); - static void entityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags); + static ScriptValuePointer entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); + static void entityPropertyFlagsFromScriptValue(const ScriptValuePointer& object, EntityPropertyFlags& flags); static bool getPropertyInfo(const QString& propertyName, EntityPropertyInfo& propertyInfo); @@ -539,18 +543,18 @@ class EntityItemProperties { }; Q_DECLARE_METATYPE(EntityItemProperties); -QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); -QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue& object, EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue& object, EntityItemProperties& properties); +ScriptValuePointer EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); +ScriptValuePointer EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); +void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValuePointer& object, EntityItemProperties& properties); +void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValuePointer& object, EntityItemProperties& properties); Q_DECLARE_METATYPE(EntityPropertyFlags); -QScriptValue EntityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags); -void EntityPropertyFlagsFromScriptValue(const QScriptValue& object, EntityPropertyFlags& flags); +ScriptValuePointer EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); +void EntityPropertyFlagsFromScriptValue(const ScriptValuePointer& object, EntityPropertyFlags& flags); Q_DECLARE_METATYPE(EntityPropertyInfo); -QScriptValue EntityPropertyInfoToScriptValue(QScriptEngine* engine, const EntityPropertyInfo& propertyInfo); -void EntityPropertyInfoFromScriptValue(const QScriptValue& object, EntityPropertyInfo& propertyInfo); +ScriptValuePointer EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo); +void EntityPropertyInfoFromScriptValue(const ScriptValuePointer& object, EntityPropertyInfo& propertyInfo); // define these inline here so the macros work inline void EntityItemProperties::setPosition(const glm::vec3& value) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index c25eb21e6c5..550e822ff2d 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -15,6 +15,9 @@ #include "EntityItemID.h" #include +#include "ScriptEngine.h" +#include "ScriptValue.h" +#include "ScriptValueUtils.h" #define APPEND_ENTITY_PROPERTY(P,V) \ if (requestedProperties.getHasProperty(P)) { \ @@ -99,118 +102,118 @@ changedProperties += P; \ } -inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec2& v) { return vec2ToScriptValue(e, v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3ToScriptValue(e, v); } -inline QScriptValue vec3Color_convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3ColorToScriptValue(e, v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::u8vec3& v) { return u8vec3ToScriptValue(e, v); } -inline QScriptValue u8vec3Color_convertScriptValue(QScriptEngine* e, const glm::u8vec3& v) { return u8vec3ColorToScriptValue(e, v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, bool v) { return QScriptValue(v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, quint16 v) { return QScriptValue(v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, quint32 v) { return QScriptValue(v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, quint64 v) { return QScriptValue((qsreal)v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { return QScriptValue(v); } - -inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; } -inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorVec3ToScriptValue(e, v); } -inline QScriptValue qVectorVec3Color_convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorVec3ColorToScriptValue(e, v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorQuatToScriptValue(e, v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorBoolToScriptValue(e, v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) { return qVectorQUuidToScriptValue(e, v); } - -inline QScriptValue convertScriptValue(QScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); } - -inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const glm::vec2& v) { return vec2ToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ToScriptValue(e, v); } +inline ScriptValuePointer vec3Color_convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ColorToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ToScriptValue(e, v); } +inline ScriptValuePointer u8vec3Color_convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ColorToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, float v) { return e->newValue(v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, int v) { return e->newValue(v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, bool v) { return e->newValue(v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, quint16 v) { return e->newValue(v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, quint32 v) { return e->newValue(v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, quint64 v) { return e->newValue((double)v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QString& v) { return e->newValue(v); } + +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const ScriptValuePointer& v) { return v; } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorVec3ToScriptValue(e, v); } +inline ScriptValuePointer qVectorVec3Color_convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorVec3ColorToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorQuatToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorBoolToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorQUuidToScriptValue(e, v); } + +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); } + +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QByteArray& v) { QByteArray b64 = v.toBase64(); - return QScriptValue(QString(b64)); + return e->newValue(QString(b64)); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) { return QScriptValue(QUuid(v).toString()); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const EntityItemID& v) { return e->newValue(QUuid(v).toString()); } -inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { return aaCubeToScriptValue(e, v); } +inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const AACube& v) { return aaCubeToScriptValue(e, v); } #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(X,G,g,P,p) \ if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \ (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \ - QScriptValue groupProperties = properties.property(#g); \ - if (!groupProperties.isValid()) { \ + ScriptValuePointer groupProperties = properties->property(#g); \ + if (!groupProperties->isValid()) { \ groupProperties = engine->newObject(); \ } \ - QScriptValue V = convertScriptValue(engine, get##P()); \ - groupProperties.setProperty(#p, V); \ - properties.setProperty(#g, groupProperties); \ + ScriptValuePointer V = convertScriptValue(engine, get##P()); \ + groupProperties->setProperty(#p, V); \ + properties->setProperty(#g, groupProperties); \ } #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(X,G,g,P,p,T) \ if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \ (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \ - QScriptValue groupProperties = properties.property(#g); \ - if (!groupProperties.isValid()) { \ + ScriptValuePointer groupProperties = properties->property(#g); \ + if (!groupProperties->isValid()) { \ groupProperties = engine->newObject(); \ } \ - QScriptValue V = T##_convertScriptValue(engine, get##P()); \ - groupProperties.setProperty(#p, V); \ - properties.setProperty(#g, groupProperties); \ + ScriptValuePointer V = T##_convertScriptValue(engine, get##P()); \ + groupProperties->setProperty(#p, V); \ + properties->setProperty(#g, groupProperties); \ } #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(X,G,g,P,p,M) \ if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \ (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \ - QScriptValue groupProperties = properties.property(#g); \ - if (!groupProperties.isValid()) { \ + ScriptValuePointer groupProperties = properties->property(#g); \ + if (!groupProperties->isValid()) { \ groupProperties = engine->newObject(); \ } \ - QScriptValue V = convertScriptValue(engine, M()); \ - groupProperties.setProperty(#p, V); \ - properties.setProperty(#g, groupProperties); \ + ScriptValuePointer V = convertScriptValue(engine, M()); \ + groupProperties->setProperty(#p, V); \ + properties->setProperty(#g, groupProperties); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE(p,P) \ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - QScriptValue V = convertScriptValue(engine, _##P); \ - properties.setProperty(#P, V); \ + ScriptValuePointer V = convertScriptValue(engine, _##P); \ + properties->setProperty(#P, V); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(p,P,T) \ if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - QScriptValue V = T##_convertScriptValue(engine, _##P); \ - properties.setProperty(#P, V); \ + ScriptValuePointer V = T##_convertScriptValue(engine, _##P); \ + properties->setProperty(#P, V); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(P, G) \ - properties.setProperty(#P, G); + properties->setProperty(#P, G); #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, G) \ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - QScriptValue V = convertScriptValue(engine, G); \ - properties.setProperty(#P, V); \ + ScriptValuePointer V = convertScriptValue(engine, G); \ + properties->setProperty(#P, V); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(p, P, G, T) \ if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - QScriptValue V = T##_convertScriptValue(engine, G); \ - properties.setProperty(#P, V); \ + ScriptValuePointer V = T##_convertScriptValue(engine, G); \ + properties->setProperty(#P, V); \ } // same as COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER but uses #X instead of #P in the setProperty() step #define COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, X, G) \ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - QScriptValue V = convertScriptValue(engine, G); \ - properties.setProperty(#X, V); \ + ScriptValuePointer V = convertScriptValue(engine, G); \ + properties->setProperty(#X, V); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(P, G) \ if (!skipDefaults || defaultEntityProperties._##P != _##P) { \ - QScriptValue V = convertScriptValue(engine, G); \ - properties.setProperty(#P, V); \ + ScriptValuePointer V = convertScriptValue(engine, G); \ + properties->setProperty(#P, V); \ } typedef QVector qVectorVec3; @@ -218,100 +221,100 @@ typedef QVector qVectorQuat; typedef QVector qVectorBool; typedef QVector qVectorFloat; typedef QVector qVectorQUuid; -inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); } -inline quint64 quint64_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); } -inline quint32 quint32_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline float float_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toFloat(&isValid); } +inline quint64 quint64_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toULongLong(&isValid); } +inline quint32 quint32_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { // Use QString::toUInt() so that isValid is set to false if the number is outside the quint32 range. - return v.toString().toUInt(&isValid); + return v->toString().toUInt(&isValid); } -inline quint16 quint16_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } -inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } -inline uint32_t uint32_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } -inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } -inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); } -inline uint8_t uint8_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v.toVariant().toInt(&isValid)); } -inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); } -inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } -inline EntityItemID EntityItemID_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } - -inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline quint16 quint16_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toInt(&isValid); } +inline uint16_t uint16_t_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toInt(&isValid); } +inline uint32_t uint32_t_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toInt(&isValid); } +inline int int_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toInt(&isValid); } +inline bool bool_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return v->toVariant().toBool(); } +inline uint8_t uint8_t_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v->toVariant().toInt(&isValid)); } +inline QString QString_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return v->toVariant().toString().trimmed(); } +inline QUuid QUuid_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return v->toVariant().toUuid(); } +inline EntityItemID EntityItemID_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return v->toVariant().toUuid(); } + +inline QByteArray QByteArray_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; - QString b64 = v.toVariant().toString().trimmed(); + QString b64 = v->toVariant().toString().trimmed(); return QByteArray::fromBase64(b64.toUtf8()); } -inline glm::vec2 vec2_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline glm::vec2 vec2_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; glm::vec2 vec2; vec2FromScriptValue(v, vec2); return vec2; } -inline glm::vec3 vec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline glm::vec3 vec3_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; glm::vec3 vec3; vec3FromScriptValue(v, vec3); return vec3; } -inline glm::vec3 vec3Color_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline glm::vec3 vec3Color_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; glm::vec3 vec3; vec3FromScriptValue(v, vec3); return vec3; } -inline glm::u8vec3 u8vec3Color_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline glm::u8vec3 u8vec3Color_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; glm::u8vec3 vec3; u8vec3FromScriptValue(v, vec3); return vec3; } -inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline AACube AACube_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; AACube result; aaCubeFromScriptValue(v, result); return result; } -inline qVectorFloat qVectorFloat_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline qVectorFloat qVectorFloat_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return qVectorFloatFromScriptValue(v); } -inline qVectorVec3 qVectorVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline qVectorVec3 qVectorVec3_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return qVectorVec3FromScriptValue(v); } -inline qVectorQuat qVectorQuat_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline qVectorQuat qVectorQuat_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return qVectorQuatFromScriptValue(v); } -inline qVectorBool qVectorBool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline qVectorBool qVectorBool_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return qVectorBoolFromScriptValue(v); } -inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return qVectorQUuidFromScriptValue(v); } -inline glm::quat quat_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline glm::quat quat_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = false; /// assume it can't be converted - QScriptValue x = v.property("x"); - QScriptValue y = v.property("y"); - QScriptValue z = v.property("z"); - QScriptValue w = v.property("w"); - if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { + ScriptValuePointer x = v->property("x"); + ScriptValuePointer y = v->property("y"); + ScriptValuePointer z = v->property("z"); + ScriptValuePointer w = v->property("w"); + if (x->isValid() && y->isValid() && z->isValid() && w->isValid()) { glm::quat newValue; - newValue.x = x.toVariant().toFloat(); - newValue.y = y.toVariant().toFloat(); - newValue.z = z.toVariant().toFloat(); - newValue.w = w.toVariant().toFloat(); + newValue.x = x->toVariant().toFloat(); + newValue.y = y->toVariant().toFloat(); + newValue.z = z->toVariant().toFloat(); + newValue.w = w->toVariant().toFloat(); isValid = !glm::isnan(newValue.x) && !glm::isnan(newValue.y) && !glm::isnan(newValue.z) && @@ -323,7 +326,7 @@ inline glm::quat quat_convertFromScriptValue(const QScriptValue& v, bool& isVali return glm::quat(); } -inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) { +inline QRect QRect_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; QRect rect; qRectFromScriptValue(v, rect); @@ -341,8 +344,8 @@ inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) #define COPY_PROPERTY_FROM_QSCRIPTVALUE(P, T, S) \ { \ - QScriptValue V = object.property(#P); \ - if (V.isValid()) { \ + ScriptValuePointer V = object->property(#P); \ + if (V->isValid()) { \ bool isValid = false; \ T newValue = T##_convertFromScriptValue(V, isValid); \ if (isValid && (_defaultSettings || newValue != _##P)) { \ @@ -353,8 +356,8 @@ inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) #define COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(P, T, S, G) \ { \ - QScriptValue V = object.property(#P); \ - if (V.isValid()) { \ + ScriptValuePointer V = object->property(#P); \ + if (V->isValid()) { \ bool isValid = false; \ T newValue = T##_convertFromScriptValue(V, isValid); \ if (isValid && (_defaultSettings || newValue != G())) { \ @@ -365,8 +368,8 @@ inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) #define COPY_PROPERTY_FROM_QSCRIPTVALUE_NOCHECK(P, T, S) \ { \ - QScriptValue V = object.property(#P); \ - if (V.isValid()) { \ + ScriptValuePointer V = object->property(#P); \ + if (V->isValid()) { \ bool isValid = false; \ T newValue = T##_convertFromScriptValue(V, isValid); \ if (isValid && (_defaultSettings)) { \ @@ -377,10 +380,10 @@ inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) #define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(G, P, T, S) \ { \ - QScriptValue G = object.property(#G); \ - if (G.isValid()) { \ - QScriptValue V = G.property(#P); \ - if (V.isValid()) { \ + ScriptValuePointer G = object->property(#G); \ + if (G->isValid()) { \ + ScriptValuePointer V = G->property(#P); \ + if (V->isValid()) { \ bool isValid = false; \ T newValue = T##_convertFromScriptValue(V, isValid); \ if (isValid && (_defaultSettings || newValue != _##P)) { \ @@ -392,9 +395,9 @@ inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) #define COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(P, S) \ { \ - QScriptValue P = object.property(#P); \ - if (P.isValid()) { \ - QString newValue = P.toVariant().toString(); \ + ScriptValuePointer P = object->property(#P); \ + if (P->isValid()) { \ + QString newValue = P->toVariant().toString(); \ if (_defaultSettings || newValue != get##S##AsString()) { \ set##S##FromString(newValue); \ } \ @@ -403,11 +406,11 @@ inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) #define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(G, P, S) \ { \ - QScriptValue G = object.property(#G); \ - if (G.isValid()) { \ - QScriptValue P = G.property(#P); \ - if (P.isValid()) { \ - QString newValue = P.toVariant().toString(); \ + ScriptValuePointer G = object->property(#G); \ + if (G->isValid()) { \ + ScriptValuePointer P = G->property(#P); \ + if (P->isValid()) { \ + QString newValue = P->toVariant().toString(); \ if (_defaultSettings || newValue != get##S##AsString()) { \ set##S##FromString(newValue); \ } \ diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 90c521215e9..6b4ba52f205 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -41,6 +41,9 @@ #include #include #include "GrabPropertyGroup.h" +#include +#include +#include const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}"; const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}"; @@ -672,21 +675,21 @@ struct EntityPropertiesResult { // Static method to make sure that we have the right script engine. // Using sender() or QtScriptable::engine() does not work for classes used by multiple threads (script-engines) -QScriptValue EntityScriptingInterface::getMultipleEntityProperties(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer EntityScriptingInterface::getMultipleEntityProperties(ScriptContext* context, ScriptEngine* engine) { const int ARGUMENT_ENTITY_IDS = 0; const int ARGUMENT_EXTENDED_DESIRED_PROPERTIES = 1; auto entityScriptingInterface = DependencyManager::get(); - const auto entityIDs = qscriptvalue_cast>(context->argument(ARGUMENT_ENTITY_IDS)); + const auto entityIDs = scriptvalue_cast>(context->argument(ARGUMENT_ENTITY_IDS)); return entityScriptingInterface->getMultipleEntityPropertiesInternal(engine, entityIDs, context->argument(ARGUMENT_EXTENDED_DESIRED_PROPERTIES)); } -QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScriptEngine* engine, QVector entityIDs, const QScriptValue& extendedDesiredProperties) { +ScriptValuePointer EntityScriptingInterface::getMultipleEntityPropertiesInternal(ScriptEngine* engine, QVector entityIDs, const ScriptValuePointer& extendedDesiredProperties) { PROFILE_RANGE(script_entities, __FUNCTION__); EntityPsuedoPropertyFlags psuedoPropertyFlags; - const auto readExtendedPropertyStringValue = [&](QScriptValue extendedProperty) { - const auto extendedPropertyString = extendedProperty.toString(); + const auto readExtendedPropertyStringValue = [&](ScriptValuePointer extendedProperty) { + const auto extendedPropertyString = extendedProperty->toString(); if (extendedPropertyString == "id") { psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::ID); } else if (extendedPropertyString == "type") { @@ -716,18 +719,18 @@ QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScri } }; - if (extendedDesiredProperties.isString()) { + if (extendedDesiredProperties->isString()) { readExtendedPropertyStringValue(extendedDesiredProperties); psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FlagsActive); - } else if (extendedDesiredProperties.isArray()) { - const quint32 length = extendedDesiredProperties.property("length").toInt32(); + } else if (extendedDesiredProperties->isArray()) { + const quint32 length = extendedDesiredProperties->property("length")->toInt32(); for (quint32 i = 0; i < length; i++) { - readExtendedPropertyStringValue(extendedDesiredProperties.property(i)); + readExtendedPropertyStringValue(extendedDesiredProperties->property(i)); } psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FlagsActive); } - EntityPropertyFlags desiredProperties = qscriptvalue_cast(extendedDesiredProperties); + EntityPropertyFlags desiredProperties = scriptvalue_cast(extendedDesiredProperties); bool needsScriptSemantics = desiredProperties.getHasProperty(PROP_POSITION) || desiredProperties.getHasProperty(PROP_ROTATION) || desiredProperties.getHasProperty(PROP_LOCAL_POSITION) || @@ -774,18 +777,18 @@ QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScri }); } } - QScriptValue finalResult = engine->newArray(resultProperties.size()); + ScriptValuePointer finalResult = engine->newArray(resultProperties.size()); quint32 i = 0; if (needsScriptSemantics) { PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Script Semantics"); foreach(const auto& result, resultProperties) { - finalResult.setProperty(i++, convertPropertiesToScriptSemantics(result.properties, result.scalesWithParent) + finalResult->setProperty(i++, convertPropertiesToScriptSemantics(result.properties, result.scalesWithParent) .copyToScriptValue(engine, false, false, false, psuedoPropertyFlags)); } } else { PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Skip Script Semantics"); foreach(const auto& result, resultProperties) { - finalResult.setProperty(i++, result.properties.copyToScriptValue(engine, false, false, false, psuedoPropertyFlags)); + finalResult->setProperty(i++, result.properties.copyToScriptValue(engine, false, false, false, psuedoPropertyFlags)); } } return finalResult; @@ -1060,14 +1063,14 @@ QSizeF EntityScriptingInterface::textSize(const QUuid& id, const QString& text) return EntityTree::textSize(id, text); } -void EntityScriptingInterface::setPersistentEntitiesScriptEngine(QSharedPointer engine) { +void EntityScriptingInterface::setPersistentEntitiesScriptEngine(QSharedPointer manager) { std::lock_guard lock(_entitiesScriptEngineLock); - _persistentEntitiesScriptEngine = engine; + _persistentEntitiesScriptManager = manager; } -void EntityScriptingInterface::setNonPersistentEntitiesScriptEngine(QSharedPointer engine) { +void EntityScriptingInterface::setNonPersistentEntitiesScriptEngine(QSharedPointer manager) { std::lock_guard lock(_entitiesScriptEngineLock); - _nonPersistentEntitiesScriptEngine = engine; + _nonPersistentEntitiesScriptManager = manager; } void EntityScriptingInterface::callEntityMethod(const QUuid& id, const QString& method, const QStringList& params) { @@ -1076,7 +1079,7 @@ void EntityScriptingInterface::callEntityMethod(const QUuid& id, const QString& auto entity = getEntityTree()->findEntityByEntityItemID(id); if (entity) { std::lock_guard lock(_entitiesScriptEngineLock); - auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; if (scriptEngine) { scriptEngine->callEntityScriptMethod(id, method, params); } @@ -1124,7 +1127,7 @@ void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer auto entity = getEntityTree()->findEntityByEntityItemID(entityID); if (entity) { std::lock_guard lock(_entitiesScriptEngineLock); - auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine; + auto& scriptEngine = (entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager; if (scriptEngine) { scriptEngine->callEntityScriptMethod(entityID, method, params, senderNode->getUUID()); } @@ -1258,7 +1261,7 @@ QVector EntityScriptingInterface::findEntitiesByName(const QString entity } RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, - const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) const { + const ScriptValuePointer& entityIdsToInclude, const ScriptValuePointer& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) const { PROFILE_RANGE(script_entities, __FUNCTION__); QVector entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); @@ -1334,21 +1337,21 @@ bool EntityScriptingInterface::reloadServerScripts(const QUuid& entityID) { return client->reloadServerScript(entityID); } -bool EntityPropertyMetadataRequest::script(EntityItemID entityID, QScriptValue handler) { +bool EntityPropertyMetadataRequest::script(EntityItemID entityID, ScriptValuePointer handler) { using LocalScriptStatusRequest = QFutureWatcher; LocalScriptStatusRequest* request = new LocalScriptStatusRequest; - QObject::connect(request, &LocalScriptStatusRequest::finished, _engine, [=]() mutable { + QObject::connect(request, &LocalScriptStatusRequest::finished, _manager, [=]() mutable { auto details = request->result().toMap(); - QScriptValue err, result; + ScriptValuePointer err, result; if (details.contains("isError")) { if (!details.contains("message")) { details["message"] = details["errorInfo"]; } - err = _engine->makeError(_engine->toScriptValue(details)); + err = _manager->engine()->makeError(_manager->engine()->toScriptValue(details)); } else { details["success"] = true; - result = _engine->toScriptValue(details); + result = _manager->engine()->toScriptValue(details); } callScopedHandlerObject(handler, err, result); request->deleteLater(); @@ -1361,19 +1364,20 @@ bool EntityPropertyMetadataRequest::script(EntityItemID entityID, QScriptValue h }, entityID); if (!request->isStarted()) { request->deleteLater(); - callScopedHandlerObject(handler, _engine->makeError("Entities Scripting Provider unavailable", "InternalError"), QScriptValue()); + auto engine = handler->engine(); + callScopedHandlerObject(handler, engine->makeError(engine->newValue("Entities Scripting Provider unavailable"), "InternalError"), ScriptValuePointer()); return false; } return true; } -bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, QScriptValue handler) { +bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, ScriptValuePointer handler) { auto client = DependencyManager::get(); auto request = client->createScriptStatusRequest(entityID); - QPointer engine = _engine; - QObject::connect(request, &GetScriptStatusRequest::finished, _engine, [=](GetScriptStatusRequest* request) mutable { - auto engine = _engine; - if (!engine) { + QPointer manager = _manager; + QObject::connect(request, &GetScriptStatusRequest::finished, _manager, [=](GetScriptStatusRequest* request) mutable { + auto manager = _manager; + if (!manager) { qCDebug(entities) << __FUNCTION__ << " -- engine destroyed while inflight" << entityID; return; } @@ -1383,7 +1387,7 @@ bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, QScript details["status"] = EntityScriptStatus_::valueToKey(request->getStatus()).toLower(); details["errorInfo"] = request->getErrorInfo(); - QScriptValue err, result; + ScriptValuePointer err, result; if (!details["success"].toBool()) { if (!details.contains("message") && details.contains("errorInfo")) { details["message"] = details["errorInfo"]; @@ -1391,9 +1395,9 @@ bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, QScript if (details["message"].toString().isEmpty()) { details["message"] = "entity server script details not found"; } - err = engine->makeError(engine->toScriptValue(details)); + err = manager->engine()->makeError(manager->engine()->toScriptValue(details)); } else { - result = engine->toScriptValue(details); + result = manager->engine()->toScriptValue(details); } callScopedHandlerObject(handler, err, result); request->deleteLater(); @@ -1402,22 +1406,23 @@ bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, QScript return true; } -bool EntityScriptingInterface::queryPropertyMetadata(const QUuid& entityID, QScriptValue property, QScriptValue scopeOrCallback, QScriptValue methodOrName) { - auto name = property.toString(); +bool EntityScriptingInterface::queryPropertyMetadata(const QUuid& entityID, ScriptValuePointer property, ScriptValuePointer scopeOrCallback, ScriptValuePointer methodOrName) { + auto name = property->toString(); auto handler = makeScopedHandlerObject(scopeOrCallback, methodOrName); - QPointer engine = dynamic_cast(handler.engine()); - if (!engine) { - qCDebug(entities) << "queryPropertyMetadata without detectable engine" << entityID << name; + QPointer manager = handler->engine()->manager(); + if (!manager) { + qCDebug(entities) << "queryPropertyMetadata without detectable script manager" << entityID << name; return false; } + auto engine = manager->engine(); #ifdef DEBUG_ENGINE_STATE connect(engine, &QObject::destroyed, this, [=]() { qDebug() << "queryPropertyMetadata -- engine destroyed!" << (!engine ? "nullptr" : "engine"); }); #endif - if (!handler.property("callback").isFunction()) { - qDebug() << "!handler.callback.isFunction" << engine; - engine->raiseException(engine->makeError("callback is not a function", "TypeError")); + if (!handler->property("callback")->isFunction()) { + qDebug() << "!handler.callback.isFunction" << manager; + engine->raiseException(engine->makeError(engine->newValue("callback is not a function"), "TypeError")); return false; } @@ -1433,26 +1438,36 @@ bool EntityScriptingInterface::queryPropertyMetadata(const QUuid& entityID, QScr // This is an async callback pattern -- so if needed C++ can easily throttle or restrict queries later. - EntityPropertyMetadataRequest request(engine); + EntityPropertyMetadataRequest request(manager); if (name == "script") { return request.script(entityID, handler); } else if (name == "serverScripts") { return request.serverScripts(entityID, handler); } else { - engine->raiseException(engine->makeError("metadata for property " + name + " is not yet queryable")); + engine->raiseException(engine->makeError(engine->newValue("metadata for property " + name + " is not yet queryable"))); engine->maybeEmitUncaughtException(__FUNCTION__); return false; } } -bool EntityScriptingInterface::getServerScriptStatus(const QUuid& entityID, QScriptValue callback) { +bool EntityScriptingInterface::getServerScriptStatus(const QUuid& entityID, ScriptValuePointer callback) { auto client = DependencyManager::get(); auto request = client->createScriptStatusRequest(entityID); - connect(request, &GetScriptStatusRequest::finished, callback.engine(), [callback](GetScriptStatusRequest* request) mutable { - QString statusString = EntityScriptStatus_::valueToKey(request->getStatus());; - QScriptValueList args { request->getResponseReceived(), request->getIsRunning(), statusString.toLower(), request->getErrorInfo() }; - callback.call(QScriptValue(), args); + + auto engine = callback->engine(); + auto manager = engine->manager(); + if (!manager) { + engine->raiseException(engine->makeError(engine->newValue("This script does not belong to a ScriptManager"))); + engine->maybeEmitUncaughtException(__FUNCTION__); + return false; + } + + connect(request, &GetScriptStatusRequest::finished, manager, [callback](GetScriptStatusRequest* request) mutable { + QString statusString = EntityScriptStatus_::valueToKey(request->getStatus()); + auto engine = callback->engine(); + ScriptValueList args { engine->newValue(request->getResponseReceived()), engine->newValue(request->getIsRunning()), engine->newValue(statusString.toLower()), engine->newValue(request->getErrorInfo()) }; + callback->call(ScriptValuePointer(), args); request->deleteLater(); }); request->start(); @@ -1483,40 +1498,40 @@ bool EntityScriptingInterface::getDrawZoneBoundaries() const { return ZoneEntityItem::getDrawZoneBoundaries(); } -QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, const RayToEntityIntersectionResult& value) { - QScriptValue obj = engine->newObject(); - obj.setProperty("intersects", value.intersects); - obj.setProperty("accurate", value.accurate); - QScriptValue entityItemValue = EntityItemIDtoScriptValue(engine, value.entityID); - obj.setProperty("entityID", entityItemValue); - obj.setProperty("distance", value.distance); - obj.setProperty("face", boxFaceToString(value.face)); - - QScriptValue intersection = vec3ToScriptValue(engine, value.intersection); - obj.setProperty("intersection", intersection); - QScriptValue surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); - obj.setProperty("surfaceNormal", surfaceNormal); - obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); +ScriptValuePointer RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, const RayToEntityIntersectionResult& value) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("intersects", value.intersects); + obj->setProperty("accurate", value.accurate); + ScriptValuePointer entityItemValue = EntityItemIDtoScriptValue(engine, value.entityID); + obj->setProperty("entityID", entityItemValue); + obj->setProperty("distance", value.distance); + obj->setProperty("face", boxFaceToString(value.face)); + + ScriptValuePointer intersection = vec3ToScriptValue(engine, value.intersection); + obj->setProperty("intersection", intersection); + ScriptValuePointer surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); + obj->setProperty("surfaceNormal", surfaceNormal); + obj->setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); return obj; } -void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, RayToEntityIntersectionResult& value) { - value.intersects = object.property("intersects").toVariant().toBool(); - value.accurate = object.property("accurate").toVariant().toBool(); - QScriptValue entityIDValue = object.property("entityID"); +void RayToEntityIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToEntityIntersectionResult& value) { + value.intersects = object->property("intersects")->toVariant().toBool(); + value.accurate = object->property("accurate")->toVariant().toBool(); + ScriptValuePointer entityIDValue = object->property("entityID"); quuidFromScriptValue(entityIDValue, value.entityID); - value.distance = object.property("distance").toVariant().toFloat(); - value.face = boxFaceFromString(object.property("face").toVariant().toString()); + value.distance = object->property("distance")->toVariant().toFloat(); + value.face = boxFaceFromString(object->property("face")->toVariant().toString()); - QScriptValue intersection = object.property("intersection"); - if (intersection.isValid()) { + ScriptValuePointer intersection = object->property("intersection"); + if (intersection->isValid()) { vec3FromScriptValue(intersection, value.intersection); } - QScriptValue surfaceNormal = object.property("surfaceNormal"); - if (surfaceNormal.isValid()) { + ScriptValuePointer surfaceNormal = object->property("surfaceNormal"); + if (surfaceNormal->isValid()) { vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } - value.extraInfo = object.property("extraInfo").toVariant().toMap(); + value.extraInfo = object->property("extraInfo")->toVariant().toMap(); } bool EntityScriptingInterface::polyVoxWorker(QUuid entityID, std::function actor) { @@ -2237,14 +2252,15 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons return aaBox.findCapsulePenetration(start, end, radius, penetration); } -void EntityScriptingInterface::getMeshes(const QUuid& entityID, QScriptValue callback) { +void EntityScriptingInterface::getMeshes(const QUuid& entityID, ScriptValuePointer callback) { PROFILE_RANGE(script_entities, __FUNCTION__); + auto engine = callback->engine(); EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::getMeshes no entity with ID" << entityID; - QScriptValueList args { callback.engine()->undefinedValue(), false }; - callback.call(QScriptValue(), args); + ScriptValueList args { engine->undefinedValue(), false }; + callback->call(ScriptValuePointer(), args); return; } @@ -2252,12 +2268,12 @@ void EntityScriptingInterface::getMeshes(const QUuid& entityID, QScriptValue cal bool success = entity->getMeshes(result); if (success) { - QScriptValue resultAsScriptValue = meshesToScriptValue(callback.engine(), result); - QScriptValueList args { resultAsScriptValue, true }; - callback.call(QScriptValue(), args); + ScriptValuePointer resultAsScriptValue = meshesToScriptValue(engine.data(), result); + ScriptValueList args{ resultAsScriptValue, engine->newValue(true) }; + callback->call(ScriptValuePointer(), args); } else { - QScriptValueList args { callback.engine()->undefinedValue(), false }; - callback.call(QScriptValue(), args); + ScriptValueList args { engine->undefinedValue(), engine->newValue(false) }; + callback->call(ScriptValuePointer(), args); } } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 4647e263355..cba590f30a9 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -19,13 +19,15 @@ #include #include #include +#include #include #include #include #include -#include +#include "PointerEvent.h" #include +#include "ScriptManager.h" #include "PolyVoxEntityItem.h" #include "LineEntityItem.h" @@ -36,10 +38,12 @@ #include "EntitiesScriptEngineProvider.h" #include "EntityItemProperties.h" -#include "BaseScriptEngine.h" - class EntityTree; class MeshProxy; +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; extern const QString GRABBABLE_USER_DATA; extern const QString NOT_GRABBABLE_USER_DATA; @@ -50,11 +54,11 @@ extern const QString NOT_GRABBABLE_USER_DATA; // problems with their own Entity scripts. class EntityPropertyMetadataRequest { public: - EntityPropertyMetadataRequest(BaseScriptEngine* engine) : _engine(engine) {}; - bool script(EntityItemID entityID, QScriptValue handler); - bool serverScripts(EntityItemID entityID, QScriptValue handler); + EntityPropertyMetadataRequest(ScriptManager* manager) : _manager(manager == nullptr ? nullptr : manager){}; + bool script(EntityItemID entityID, ScriptValuePointer handler); + bool serverScripts(EntityItemID entityID, ScriptValuePointer handler); private: - QPointer _engine; + QPointer _manager; }; /**jsdoc @@ -85,8 +89,8 @@ class RayToEntityIntersectionResult { QVariantMap extraInfo; }; Q_DECLARE_METATYPE(RayToEntityIntersectionResult) -QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, const RayToEntityIntersectionResult& results); -void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, RayToEntityIntersectionResult& results); +ScriptValuePointer RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, const RayToEntityIntersectionResult& results); +void RayToEntityIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToEntityIntersectionResult& results); class ParabolaToEntityIntersectionResult { public: @@ -181,8 +185,8 @@ class EntityScriptingInterface : public OctreeScriptingInterface, public Depende void setEntityTree(EntityTreePointer modelTree); EntityTreePointer getEntityTree() { return _entityTree; } - void setPersistentEntitiesScriptEngine(QSharedPointer engine); - void setNonPersistentEntitiesScriptEngine(QSharedPointer engine); + void setPersistentEntitiesScriptEngine(QSharedPointer manager); + void setNonPersistentEntitiesScriptEngine(QSharedPointer manager); void resetActivityTracking(); ActivityTracking getActivityTracking() const { return _activityTracking; } @@ -208,8 +212,8 @@ class EntityScriptingInterface : public OctreeScriptingInterface, public Depende * var propertySets = Entities.getMultipleEntityProperties(entityIDs, "name"); * print("Nearby entity names: " + JSON.stringify(propertySets)); */ - static QScriptValue getMultipleEntityProperties(QScriptContext* context, QScriptEngine* engine); - QScriptValue getMultipleEntityPropertiesInternal(QScriptEngine* engine, QVector entityIDs, const QScriptValue& extendedDesiredProperties); + static ScriptValuePointer getMultipleEntityProperties(ScriptContext* context, ScriptEngine* engine); + ScriptValuePointer getMultipleEntityPropertiesInternal(ScriptEngine* engine, QVector entityIDs, const ScriptValuePointer& extendedDesiredProperties); QUuid addEntityInternal(const EntityItemProperties& properties, entity::HostType entityHostType); @@ -834,7 +838,7 @@ public slots: /// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate /// will be false. Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false, - const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue(), + const ScriptValuePointer& entityIdsToInclude = ScriptValuePointer(), const ScriptValuePointer& entityIdsToDiscard = ScriptValuePointer(), bool visibleOnly = false, bool collidableOnly = false) const; /**jsdoc @@ -863,7 +867,7 @@ public slots: * @param {string} errorInfo - "" if there is a server entity script running, otherwise it may contain extra * information on the error. */ - Q_INVOKABLE bool getServerScriptStatus(const QUuid& entityID, QScriptValue callback); + Q_INVOKABLE bool getServerScriptStatus(const QUuid& entityID, ScriptValuePointer callback); /**jsdoc * Gets metadata for certain entity properties such as script and serverScripts. @@ -893,8 +897,8 @@ public slots: * @param {object} result - The metadata for the requested entity property if there was no error, otherwise * undefined. */ - Q_INVOKABLE bool queryPropertyMetadata(const QUuid& entityID, QScriptValue property, QScriptValue scopeOrCallback, - QScriptValue methodOrName = QScriptValue()); + Q_INVOKABLE bool queryPropertyMetadata(const QUuid& entityID, ScriptValuePointer property, ScriptValuePointer scopeOrCallback, + ScriptValuePointer methodOrName = ScriptValuePointer()); /**jsdoc @@ -1907,7 +1911,7 @@ public slots: * {@link Graphics} API instead. */ // FIXME move to a renderable entity interface - Q_INVOKABLE void getMeshes(const QUuid& entityID, QScriptValue callback); + Q_INVOKABLE void getMeshes(const QUuid& entityID, ScriptValuePointer callback); /**jsdoc * Gets the object to world transform, excluding scale, of an entity. @@ -2532,7 +2536,7 @@ public slots: auto entity = getEntityTree()->findEntityByEntityItemID(id); if (entity) { std::lock_guard lock(_entitiesScriptEngineLock); - function((entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptEngine : _nonPersistentEntitiesScriptEngine); + function((entity->isLocalEntity() || entity->isMyAvatarEntity()) ? _persistentEntitiesScriptManager : _nonPersistentEntitiesScriptManager); } }; @@ -2563,8 +2567,8 @@ private slots: EntityTreePointer _entityTree; std::recursive_mutex _entitiesScriptEngineLock; - QSharedPointer _persistentEntitiesScriptEngine; - QSharedPointer _nonPersistentEntitiesScriptEngine; + QSharedPointer _persistentEntitiesScriptManager; + QSharedPointer _nonPersistentEntitiesScriptManager; bool _bidOnSimulationOwnership { false }; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index eeb42626c25..13fca731588 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -23,8 +23,6 @@ #include #include -#include - #include #include #include @@ -2848,8 +2846,8 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer } entityDescription["DataVersion"] = _persistDataVersion; entityDescription["Id"] = _persistID; - QScriptEngine scriptEngine; - RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues, + ScriptEnginePointer engine = newScriptEngine(); + RecurseOctreeToMapOperator theOperator(entityDescription, element, engine.data(), skipDefaultValues, skipThoseWithBadParents, _myAvatar); withReadLock([&] { recurseTreeWithOperator(&theOperator); @@ -2995,10 +2993,10 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { // map will have a top-level list keyed as "Entities". This will be extracted // and iterated over. Each member of this list is converted to a QVariantMap, then - // to a QScriptValue, and then to EntityItemProperties. These properties are used + // to a ScriptValuePointer, and then to EntityItemProperties. These properties are used // to add the new entity to the EntityTree. QVariantList entitiesQList = map["Entities"].toList(); - QScriptEngine scriptEngine; + ScriptEnginePointer scriptEngine = newScriptEngine(); if (entitiesQList.length() == 0) { // Empty map or invalidly formed file. @@ -3009,7 +3007,7 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { bool success = true; foreach (QVariant entityVariant, entitiesQList) { - // QVariantMap --> QScriptValue --> EntityItemProperties --> Entity + // QVariantMap --> ScriptValuePointer --> EntityItemProperties --> Entity QVariantMap entityMap = entityVariant.toMap(); // handle parentJointName for wearables @@ -3022,7 +3020,7 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { " mapped it to parentJointIndex " << entityMap["parentJointIndex"].toInt(); } - QScriptValue entityScriptValue = variantMapToScriptValue(entityMap, scriptEngine); + ScriptValuePointer entityScriptValue = variantMapToScriptValue(entityMap, *scriptEngine); EntityItemProperties properties; EntityItemPropertiesFromScriptValueIgnoreReadOnly(entityScriptValue, properties); @@ -3173,8 +3171,8 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { } bool EntityTree::writeToJSON(QString& jsonString, const OctreeElementPointer& element) { - QScriptEngine scriptEngine; - RecurseOctreeToJSONOperator theOperator(element, &scriptEngine, jsonString); + ScriptEnginePointer engine = newScriptEngine(); + RecurseOctreeToJSONOperator theOperator(element, engine.data(), jsonString); withReadLock([&] { recurseTreeWithOperator(&theOperator); }); diff --git a/libraries/entities/src/GrabPropertyGroup.cpp b/libraries/entities/src/GrabPropertyGroup.cpp index 7a9ba147d9b..f18d1c2c4a2 100644 --- a/libraries/entities/src/GrabPropertyGroup.cpp +++ b/libraries/entities/src/GrabPropertyGroup.cpp @@ -16,8 +16,8 @@ #include "EntityItemProperties.h" #include "EntityItemPropertiesMacros.h" -void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, +void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic); @@ -43,7 +43,7 @@ void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProp } -void GrabPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void GrabPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabbable, bool, setGrabbable); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabKinematic, bool, setGrabKinematic); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabFollowsController, bool, setGrabFollowsController); diff --git a/libraries/entities/src/GrabPropertyGroup.h b/libraries/entities/src/GrabPropertyGroup.h index 9fa58273be1..4c8440ee935 100644 --- a/libraries/entities/src/GrabPropertyGroup.h +++ b/libraries/entities/src/GrabPropertyGroup.h @@ -16,7 +16,7 @@ #include -#include +#include #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" @@ -25,6 +25,8 @@ class EntityItemProperties; class EncodeBitstreamParams; class OctreePacketData; class ReadBitstreamToTreeParams; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; static const bool INITIAL_GRABBABLE { true }; static const bool INITIAL_KINEMATIC { true }; @@ -72,10 +74,10 @@ static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_OFFSET { glm::vec3(0.0f) }; class GrabPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const GrabPropertyGroup& other); diff --git a/libraries/entities/src/HazePropertyGroup.cpp b/libraries/entities/src/HazePropertyGroup.cpp index 632f73ced6e..d9b939babcc 100644 --- a/libraries/entities/src/HazePropertyGroup.cpp +++ b/libraries/entities/src/HazePropertyGroup.cpp @@ -16,7 +16,7 @@ #include "EntityItemProperties.h" #include "EntityItemPropertiesMacros.h" -void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_RANGE, Haze, haze, HazeRange, hazeRange); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_HAZE_COLOR, Haze, haze, HazeColor, hazeColor, u8vec3Color); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_HAZE_GLARE_COLOR, Haze, haze, HazeGlareColor, hazeGlareColor, u8vec3Color); @@ -34,7 +34,7 @@ void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProp COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude); } -void HazePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void HazePropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeRange, float, setHazeRange); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeColor, u8vec3Color, setHazeColor); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeGlareColor, u8vec3Color, setHazeGlareColor); diff --git a/libraries/entities/src/HazePropertyGroup.h b/libraries/entities/src/HazePropertyGroup.h index 59a36b6f7f9..a30b20a9c25 100644 --- a/libraries/entities/src/HazePropertyGroup.h +++ b/libraries/entities/src/HazePropertyGroup.h @@ -16,7 +16,7 @@ #include -#include +#include #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" @@ -26,6 +26,9 @@ class EncodeBitstreamParams; class OctreePacketData; class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; static const float INITIAL_HAZE_RANGE{ 1000.0f }; static const glm::u8vec3 initialHazeGlareColor { 255, 229, 179 }; @@ -76,10 +79,10 @@ static const float INITIAL_KEY_LIGHT_ALTITUDE{ 200.0f }; class HazePropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const HazePropertyGroup& other); diff --git a/libraries/entities/src/KeyLightPropertyGroup.cpp b/libraries/entities/src/KeyLightPropertyGroup.cpp index b70e94504df..f688b47af36 100644 --- a/libraries/entities/src/KeyLightPropertyGroup.cpp +++ b/libraries/entities/src/KeyLightPropertyGroup.cpp @@ -25,8 +25,8 @@ const bool KeyLightPropertyGroup::DEFAULT_KEYLIGHT_CAST_SHADOWS { false }; const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_SHADOW_BIAS { 0.5f }; const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_SHADOW_MAX_DISTANCE { 40.0f }; -void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_KEYLIGHT_COLOR, KeyLight, keyLight, Color, color, u8vec3Color); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_INTENSITY, KeyLight, keyLight, Intensity, intensity); @@ -36,7 +36,7 @@ void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desired COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, KeyLight, keyLight, ShadowMaxDistance, shadowMaxDistance); } -void KeyLightPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void KeyLightPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, color, u8vec3Color, setColor); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, intensity, float, setIntensity); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, direction, vec3, setDirection); diff --git a/libraries/entities/src/KeyLightPropertyGroup.h b/libraries/entities/src/KeyLightPropertyGroup.h index 6441c30d509..2760f8ac9b6 100644 --- a/libraries/entities/src/KeyLightPropertyGroup.h +++ b/libraries/entities/src/KeyLightPropertyGroup.h @@ -17,7 +17,7 @@ #include -#include +#include #include "EntityItemPropertiesMacros.h" #include "PropertyGroup.h" @@ -26,6 +26,9 @@ class EncodeBitstreamParams; class OctreePacketData; class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * A key light is defined by the following properties: @@ -45,10 +48,10 @@ class ReadBitstreamToTreeParams; class KeyLightPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const KeyLightPropertyGroup& other); diff --git a/libraries/entities/src/PropertyGroup.h b/libraries/entities/src/PropertyGroup.h index 8a9d7e9158c..9d74388caac 100644 --- a/libraries/entities/src/PropertyGroup.h +++ b/libraries/entities/src/PropertyGroup.h @@ -12,7 +12,7 @@ #ifndef hifi_PropertyGroup_h #define hifi_PropertyGroup_h -#include +#include #include @@ -24,6 +24,9 @@ class EncodeBitstreamParams; class OctreePacketData; class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr; @@ -32,8 +35,8 @@ class PropertyGroup { virtual ~PropertyGroup() = default; // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) = 0; + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) = 0; virtual void debugDump() const { } virtual void listChangedProperties(QList& out) { } diff --git a/libraries/entities/src/PulsePropertyGroup.cpp b/libraries/entities/src/PulsePropertyGroup.cpp index 54f81750da9..7db361df6f5 100644 --- a/libraries/entities/src/PulsePropertyGroup.cpp +++ b/libraries/entities/src/PulsePropertyGroup.cpp @@ -57,8 +57,8 @@ void PulsePropertyGroup::setAlphaModeFromString(const QString& pulseMode) { } } -void PulsePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, +void PulsePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_PULSE_MIN, Pulse, pulse, Min, min); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_PULSE_MAX, Pulse, pulse, Max, max); @@ -67,7 +67,7 @@ void PulsePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredPro COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PULSE_ALPHA_MODE, Pulse, pulse, AlphaMode, alphaMode, getAlphaModeAsString); } -void PulsePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void PulsePropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, min, float, setMin); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, max, float, setMax); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, period, float, setPeriod); diff --git a/libraries/entities/src/PulsePropertyGroup.h b/libraries/entities/src/PulsePropertyGroup.h index 634ab654a75..062317e639e 100644 --- a/libraries/entities/src/PulsePropertyGroup.h +++ b/libraries/entities/src/PulsePropertyGroup.h @@ -13,7 +13,7 @@ #include -#include +#include #include @@ -24,6 +24,9 @@ class EntityItemProperties; class EncodeBitstreamParams; class OctreePacketData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * A color and alpha pulse that an entity may have. @@ -40,10 +43,10 @@ class ReadBitstreamToTreeParams; class PulsePropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const PulsePropertyGroup& other); diff --git a/libraries/entities/src/RecurseOctreeToJSONOperator.cpp b/libraries/entities/src/RecurseOctreeToJSONOperator.cpp index b64a700abcc..7e91a8d0482 100644 --- a/libraries/entities/src/RecurseOctreeToJSONOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToJSONOperator.cpp @@ -11,8 +11,9 @@ #include "RecurseOctreeToJSONOperator.h" #include "EntityItemProperties.h" +#include -RecurseOctreeToJSONOperator::RecurseOctreeToJSONOperator(const OctreeElementPointer&, QScriptEngine* engine, +RecurseOctreeToJSONOperator::RecurseOctreeToJSONOperator(const OctreeElementPointer&, ScriptEngine* engine, QString jsonPrefix, bool skipDefaults, bool skipThoseWithBadParents): _engine(engine), _json(jsonPrefix), @@ -34,7 +35,7 @@ void RecurseOctreeToJSONOperator::processEntity(const EntityItemPointer& entity) return; // we weren't able to resolve a parent from _parentID, so don't save this entity. } - QScriptValue qScriptValues = _skipDefaults + ScriptValuePointer qScriptValues = _skipDefaults ? EntityItemNonDefaultPropertiesToScriptValue(_engine, entity->getProperties()) : EntityItemPropertiesToScriptValue(_engine, entity->getProperties()); @@ -45,6 +46,6 @@ void RecurseOctreeToJSONOperator::processEntity(const EntityItemPointer& entity) _json += "\n "; // Override default toString(): - qScriptValues.setProperty("toString", _toStringMethod); - _json += qScriptValues.toString(); + qScriptValues->setProperty("toString", _toStringMethod); + _json += qScriptValues->toString(); } diff --git a/libraries/entities/src/RecurseOctreeToJSONOperator.h b/libraries/entities/src/RecurseOctreeToJSONOperator.h index a1d388ed222..4f4fce5b425 100644 --- a/libraries/entities/src/RecurseOctreeToJSONOperator.h +++ b/libraries/entities/src/RecurseOctreeToJSONOperator.h @@ -11,9 +11,15 @@ #include "EntityTree.h" +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + class RecurseOctreeToJSONOperator : public RecurseOctreeOperator { public: - RecurseOctreeToJSONOperator(const OctreeElementPointer&, QScriptEngine* engine, QString jsonPrefix = QString(), bool skipDefaults = true, + RecurseOctreeToJSONOperator(const OctreeElementPointer&, ScriptEngine* engine, QString jsonPrefix = QString(), bool skipDefaults = true, bool skipThoseWithBadParents = false); virtual bool preRecursion(const OctreeElementPointer& element) override { return true; }; virtual bool postRecursion(const OctreeElementPointer& element) override; @@ -23,8 +29,8 @@ class RecurseOctreeToJSONOperator : public RecurseOctreeOperator { private: void processEntity(const EntityItemPointer& entity); - QScriptEngine* _engine; - QScriptValue _toStringMethod; + ScriptEngine* _engine; + ScriptValuePointer _toStringMethod; QString _json; const bool _skipDefaults; diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.cpp b/libraries/entities/src/RecurseOctreeToMapOperator.cpp index 5be921112fc..e8f1a483f89 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToMapOperator.cpp @@ -12,10 +12,11 @@ #include "RecurseOctreeToMapOperator.h" #include "EntityItemProperties.h" +#include RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map, const OctreeElementPointer& top, - QScriptEngine* engine, + ScriptEngine* engine, bool skipDefaultValues, bool skipThoseWithBadParents, std::shared_ptr myAvatar) : @@ -56,7 +57,7 @@ bool RecurseOctreeToMapOperator::postRecursion(const OctreeElementPointer& eleme } EntityItemProperties properties = entityItem->getProperties(); - QScriptValue qScriptValues; + ScriptValuePointer qScriptValues; if (_skipDefaultValues) { qScriptValues = EntityItemNonDefaultPropertiesToScriptValue(_engine, properties); } else { @@ -70,11 +71,11 @@ bool RecurseOctreeToMapOperator::postRecursion(const OctreeElementPointer& eleme auto jointNames = _myAvatar->getJointNames(); auto parentJointIndex = entityItem->getParentJointIndex(); if (parentJointIndex < jointNames.count()) { - qScriptValues.setProperty("parentJointName", jointNames.at(parentJointIndex)); + qScriptValues->setProperty("parentJointName", jointNames.at(parentJointIndex)); } } - entitiesQList << qScriptValues.toVariant(); + entitiesQList << qScriptValues->toVariant(); }); _map["Entities"] = entitiesQList; diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.h b/libraries/entities/src/RecurseOctreeToMapOperator.h index 985ec9de35c..9fbd9f41b29 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.h +++ b/libraries/entities/src/RecurseOctreeToMapOperator.h @@ -11,16 +11,18 @@ #include "EntityTree.h" +class ScriptEngine; + class RecurseOctreeToMapOperator : public RecurseOctreeOperator { public: - RecurseOctreeToMapOperator(QVariantMap& map, const OctreeElementPointer& top, QScriptEngine* engine, bool skipDefaultValues, + RecurseOctreeToMapOperator(QVariantMap& map, const OctreeElementPointer& top, ScriptEngine* engine, bool skipDefaultValues, bool skipThoseWithBadParents, std::shared_ptr myAvatar); bool preRecursion(const OctreeElementPointer& element) override; bool postRecursion(const OctreeElementPointer& element) override; private: QVariantMap& _map; OctreeElementPointer _top; - QScriptEngine* _engine; + ScriptEngine* _engine; bool _withinTop; bool _skipDefaultValues; bool _skipThoseWithBadParents; diff --git a/libraries/entities/src/RingGizmoPropertyGroup.cpp b/libraries/entities/src/RingGizmoPropertyGroup.cpp index 387cb1d688e..1dcc443609f 100644 --- a/libraries/entities/src/RingGizmoPropertyGroup.cpp +++ b/libraries/entities/src/RingGizmoPropertyGroup.cpp @@ -20,8 +20,8 @@ const float RingGizmoPropertyGroup::MAX_ALPHA = 1.0f; const float RingGizmoPropertyGroup::MIN_RADIUS = 0.0f; const float RingGizmoPropertyGroup::MAX_RADIUS = 0.5f; -void RingGizmoPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, +void RingGizmoPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_START_ANGLE, Ring, ring, StartAngle, startAngle); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_END_ANGLE, Ring, ring, EndAngle, endAngle); @@ -46,7 +46,7 @@ void RingGizmoPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_MINOR_TICK_MARKS_COLOR, Ring, ring, MinorTickMarksColor, minorTickMarksColor, u8vec3Color); } -void RingGizmoPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void RingGizmoPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, startAngle, float, setStartAngle); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, endAngle, float, setEndAngle); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, innerRadius, float, setInnerRadius); diff --git a/libraries/entities/src/RingGizmoPropertyGroup.h b/libraries/entities/src/RingGizmoPropertyGroup.h index 1f23152fc71..064ef79f271 100644 --- a/libraries/entities/src/RingGizmoPropertyGroup.h +++ b/libraries/entities/src/RingGizmoPropertyGroup.h @@ -11,7 +11,7 @@ #include -#include +#include #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" @@ -21,6 +21,9 @@ class EntityItemProperties; class EncodeBitstreamParams; class OctreePacketData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; using u8vec3Color = glm::u8vec3; @@ -56,10 +59,10 @@ using u8vec3Color = glm::u8vec3; class RingGizmoPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const RingGizmoPropertyGroup& other); diff --git a/libraries/entities/src/SkyboxPropertyGroup.cpp b/libraries/entities/src/SkyboxPropertyGroup.cpp index 89ffa95dbe9..4cd16c75791 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.cpp +++ b/libraries/entities/src/SkyboxPropertyGroup.cpp @@ -18,12 +18,12 @@ const glm::u8vec3 SkyboxPropertyGroup::DEFAULT_COLOR = { 0, 0, 0 }; -void SkyboxPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void SkyboxPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color, u8vec3Color); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_SKYBOX_URL, Skybox, skybox, URL, url); } -void SkyboxPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { +void SkyboxPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(skybox, color, u8vec3Color, setColor); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(skybox, url, QString, setURL); } diff --git a/libraries/entities/src/SkyboxPropertyGroup.h b/libraries/entities/src/SkyboxPropertyGroup.h index 0c128aa7308..20d8663c73f 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.h +++ b/libraries/entities/src/SkyboxPropertyGroup.h @@ -16,7 +16,7 @@ #include -#include +#include #include @@ -28,6 +28,9 @@ class EncodeBitstreamParams; class OctreePacketData; class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * A skybox is defined by the following properties: @@ -39,10 +42,10 @@ class ReadBitstreamToTreeParams; class SkyboxPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, - QScriptEngine* engine, bool skipDefaults, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; void merge(const SkyboxPropertyGroup& other); diff --git a/libraries/graphics-scripting/src/graphics-scripting/Forward.h b/libraries/graphics-scripting/src/graphics-scripting/Forward.h index 29f80794223..89fd8d353a2 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/Forward.h +++ b/libraries/graphics-scripting/src/graphics-scripting/Forward.h @@ -22,7 +22,6 @@ using ModelPointer = std::shared_ptr; namespace gpu { class BufferView; } -class QScriptEngine; namespace scriptable { using Mesh = graphics::Mesh; diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index a27eff9cbee..522508dd1bf 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -17,15 +17,16 @@ #include "ScriptableMeshPart.h" #include #include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include -GraphicsScriptingInterface::GraphicsScriptingInterface(QObject* parent) : QObject(parent), QScriptable() { +GraphicsScriptingInterface::GraphicsScriptingInterface(QObject* parent) : QObject(parent), Scriptable() { } void GraphicsScriptingInterface::jsThrowError(const QString& error) { @@ -314,18 +315,18 @@ namespace { } namespace scriptable { - template int registerQPointerMetaType(QScriptEngine* engine) { - qScriptRegisterSequenceMetaType>>(engine); - return qScriptRegisterMetaType>( + template int registerQPointerMetaType(ScriptEngine* engine) { + scriptRegisterSequenceMetaType>>(engine); + return scriptRegisterMetaType>( engine, - [](QScriptEngine* engine, const QPointer& object) -> QScriptValue { + [](ScriptEngine* engine, const QPointer& object) -> ScriptValuePointer { if (!object) { - return QScriptValue::NullValue; + return engine->nullValue(); } - return engine->newQObject(object, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::AutoCreateDynamicProperties); + return engine->newQObject(object, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::AutoCreateDynamicProperties); }, - [](const QScriptValue& value, QPointer& out) { - auto obj = value.toQObject(); + [](const ScriptValuePointer& value, QPointer& out) { + auto obj = value->toQObject(); #ifdef SCRIPTABLE_MESH_DEBUG qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString(); #endif @@ -347,12 +348,12 @@ namespace scriptable { ); } - QScriptValue qVectorScriptableMaterialLayerToScriptValue(QScriptEngine* engine, const QVector& vector) { - return qScriptValueFromSequence(engine, vector); + ScriptValuePointer qVectorScriptableMaterialLayerToScriptValue(ScriptEngine* engine, const QVector& vector) { + return scriptValueFromSequence(engine, vector); } - void qVectorScriptableMaterialLayerFromScriptValue(const QScriptValue& array, QVector& result) { - qScriptValueToSequence(array, result); + void qVectorScriptableMaterialLayerFromScriptValue(const ScriptValuePointer& array, QVector& result) { + scriptValueToSequence(array, result); } /**jsdoc @@ -469,204 +470,204 @@ namespace scriptable { * @property {boolean} defaultFallthrough - true if all properties fall through to the material below unless * they are set, false if properties respect their individual fall-through settings. */ - QScriptValue scriptableMaterialToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterial &material) { - QScriptValue obj = engine->newObject(); - obj.setProperty("name", material.name); - obj.setProperty("model", material.model); + ScriptValuePointer scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("name", material.name); + obj->setProperty("model", material.model); bool hasPropertyFallthroughs = !material.propertyFallthroughs.empty(); - const QScriptValue FALLTHROUGH("fallthrough"); + const ScriptValuePointer FALLTHROUGH(engine->newValue("fallthrough")); if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_VAL_BIT)) { - obj.setProperty("opacity", FALLTHROUGH); + obj->setProperty("opacity", FALLTHROUGH); } else if (material.key.isTranslucentFactor()) { - obj.setProperty("opacity", material.opacity); + obj->setProperty("opacity", material.opacity); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_VAL_BIT)) { - obj.setProperty("albedo", FALLTHROUGH); + obj->setProperty("albedo", FALLTHROUGH); } else if (material.key.isAlbedo()) { - obj.setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo)); + obj->setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo)); } if (material.model.toStdString() == graphics::Material::HIFI_PBR) { if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_CUTOFF_VAL_BIT)) { - obj.setProperty("opacityCutoff", FALLTHROUGH); + obj->setProperty("opacityCutoff", FALLTHROUGH); } else if (material.key.isOpacityCutoff()) { - obj.setProperty("opacityCutoff", material.opacityCutoff); + obj->setProperty("opacityCutoff", material.opacityCutoff); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_MAP_MODE_BIT)) { - obj.setProperty("opacityMapMode", FALLTHROUGH); + obj->setProperty("opacityMapMode", FALLTHROUGH); } else if (material.key.isOpacityMapMode()) { - obj.setProperty("opacityMapMode", material.opacityMapMode); + obj->setProperty("opacityMapMode", material.opacityMapMode); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT)) { - obj.setProperty("roughness", FALLTHROUGH); + obj->setProperty("roughness", FALLTHROUGH); } else if (material.key.isGlossy()) { - obj.setProperty("roughness", material.roughness); + obj->setProperty("roughness", material.roughness); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT)) { - obj.setProperty("metallic", FALLTHROUGH); + obj->setProperty("metallic", FALLTHROUGH); } else if (material.key.isMetallic()) { - obj.setProperty("metallic", material.metallic); + obj->setProperty("metallic", material.metallic); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT)) { - obj.setProperty("scattering", FALLTHROUGH); + obj->setProperty("scattering", FALLTHROUGH); } else if (material.key.isScattering()) { - obj.setProperty("scattering", material.scattering); + obj->setProperty("scattering", material.scattering); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT)) { - obj.setProperty("unlit", FALLTHROUGH); + obj->setProperty("unlit", FALLTHROUGH); } else if (material.key.isUnlit()) { - obj.setProperty("unlit", material.unlit); + obj->setProperty("unlit", material.unlit); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT)) { - obj.setProperty("emissive", FALLTHROUGH); + obj->setProperty("emissive", FALLTHROUGH); } else if (material.key.isEmissive()) { - obj.setProperty("emissive", vec3ColorToScriptValue(engine, material.emissive)); + obj->setProperty("emissive", vec3ColorToScriptValue(engine, material.emissive)); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_MAP_BIT)) { - obj.setProperty("emissiveMap", FALLTHROUGH); + obj->setProperty("emissiveMap", FALLTHROUGH); } else if (!material.emissiveMap.isEmpty()) { - obj.setProperty("emissiveMap", material.emissiveMap); + obj->setProperty("emissiveMap", material.emissiveMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_MAP_BIT)) { - obj.setProperty("albedoMap", FALLTHROUGH); + obj->setProperty("albedoMap", FALLTHROUGH); } else if (!material.albedoMap.isEmpty()) { - obj.setProperty("albedoMap", material.albedoMap); + obj->setProperty("albedoMap", material.albedoMap); } if (!material.opacityMap.isEmpty()) { - obj.setProperty("opacityMap", material.opacityMap); + obj->setProperty("opacityMap", material.opacityMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT)) { - obj.setProperty("occlusionMap", FALLTHROUGH); + obj->setProperty("occlusionMap", FALLTHROUGH); } else if (!material.occlusionMap.isEmpty()) { - obj.setProperty("occlusionMap", material.occlusionMap); + obj->setProperty("occlusionMap", material.occlusionMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::LIGHT_MAP_BIT)) { - obj.setProperty("lightMap", FALLTHROUGH); + obj->setProperty("lightMap", FALLTHROUGH); } else if (!material.lightMap.isEmpty()) { - obj.setProperty("lightMap", material.lightMap); + obj->setProperty("lightMap", material.lightMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT)) { - obj.setProperty("scatteringMap", FALLTHROUGH); + obj->setProperty("scatteringMap", FALLTHROUGH); } else if (!material.scatteringMap.isEmpty()) { - obj.setProperty("scatteringMap", material.scatteringMap); + obj->setProperty("scatteringMap", material.scatteringMap); } // Only set one of each of these if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) { - obj.setProperty("metallicMap", FALLTHROUGH); + obj->setProperty("metallicMap", FALLTHROUGH); } else if (!material.metallicMap.isEmpty()) { - obj.setProperty("metallicMap", material.metallicMap); + obj->setProperty("metallicMap", material.metallicMap); } else if (!material.specularMap.isEmpty()) { - obj.setProperty("specularMap", material.specularMap); + obj->setProperty("specularMap", material.specularMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::ROUGHNESS_MAP_BIT)) { - obj.setProperty("roughnessMap", FALLTHROUGH); + obj->setProperty("roughnessMap", FALLTHROUGH); } else if (!material.roughnessMap.isEmpty()) { - obj.setProperty("roughnessMap", material.roughnessMap); + obj->setProperty("roughnessMap", material.roughnessMap); } else if (!material.glossMap.isEmpty()) { - obj.setProperty("glossMap", material.glossMap); + obj->setProperty("glossMap", material.glossMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::NORMAL_MAP_BIT)) { - obj.setProperty("normalMap", FALLTHROUGH); + obj->setProperty("normalMap", FALLTHROUGH); } else if (!material.normalMap.isEmpty()) { - obj.setProperty("normalMap", material.normalMap); + obj->setProperty("normalMap", material.normalMap); } else if (!material.bumpMap.isEmpty()) { - obj.setProperty("bumpMap", material.bumpMap); + obj->setProperty("bumpMap", material.bumpMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::TEXCOORDTRANSFORM0)) { - obj.setProperty("texCoordTransform0", FALLTHROUGH); + obj->setProperty("texCoordTransform0", FALLTHROUGH); } else if (material.texCoordTransforms[0] != mat4()) { - obj.setProperty("texCoordTransform0", mat4toScriptValue(engine, material.texCoordTransforms[0])); + obj->setProperty("texCoordTransform0", mat4toScriptValue(engine, material.texCoordTransforms[0])); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::TEXCOORDTRANSFORM1)) { - obj.setProperty("texCoordTransform1", FALLTHROUGH); + obj->setProperty("texCoordTransform1", FALLTHROUGH); } else if (material.texCoordTransforms[1] != mat4()) { - obj.setProperty("texCoordTransform1", mat4toScriptValue(engine, material.texCoordTransforms[1])); + obj->setProperty("texCoordTransform1", mat4toScriptValue(engine, material.texCoordTransforms[1])); } // These need to be implemented, but set the fallthrough for now if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::LIGHTMAP_PARAMS)) { - obj.setProperty("lightmapParams", FALLTHROUGH); + obj->setProperty("lightmapParams", FALLTHROUGH); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::MATERIAL_PARAMS)) { - obj.setProperty("materialParams", FALLTHROUGH); + obj->setProperty("materialParams", FALLTHROUGH); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::CULL_FACE_MODE)) { - obj.setProperty("cullFaceMode", FALLTHROUGH); + obj->setProperty("cullFaceMode", FALLTHROUGH); } else if (!material.cullFaceMode.isEmpty()) { - obj.setProperty("cullFaceMode", material.cullFaceMode); + obj->setProperty("cullFaceMode", material.cullFaceMode); } } else if (material.model.toStdString() == graphics::Material::HIFI_SHADER_SIMPLE) { - obj.setProperty("procedural", material.procedural); + obj->setProperty("procedural", material.procedural); } - obj.setProperty("defaultFallthrough", material.defaultFallthrough); + obj->setProperty("defaultFallthrough", material.defaultFallthrough); return obj; } - void scriptableMaterialFromScriptValue(const QScriptValue &object, scriptable::ScriptableMaterial& material) { - // No need to convert from QScriptValue to ScriptableMaterial + void scriptableMaterialFromScriptValue(const ScriptValuePointer &object, scriptable::ScriptableMaterial& material) { + // No need to convert from ScriptValuePointer to ScriptableMaterial } - QScriptValue scriptableMaterialLayerToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) { - QScriptValue obj = engine->newObject(); - obj.setProperty("material", scriptableMaterialToScriptValue(engine, materialLayer.material)); - obj.setProperty("priority", materialLayer.priority); + ScriptValuePointer scriptableMaterialLayerToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("material", scriptableMaterialToScriptValue(engine, materialLayer.material)); + obj->setProperty("priority", materialLayer.priority); return obj; } - void scriptableMaterialLayerFromScriptValue(const QScriptValue &object, scriptable::ScriptableMaterialLayer& materialLayer) { - // No need to convert from QScriptValue to ScriptableMaterialLayer + void scriptableMaterialLayerFromScriptValue(const ScriptValuePointer &object, scriptable::ScriptableMaterialLayer& materialLayer) { + // No need to convert from ScriptValuePointer to ScriptableMaterialLayer } - QScriptValue multiMaterialMapToScriptValue(QScriptEngine* engine, const scriptable::MultiMaterialMap& map) { - QScriptValue obj = engine->newObject(); + ScriptValuePointer multiMaterialMapToScriptValue(ScriptEngine* engine, const scriptable::MultiMaterialMap& map) { + ScriptValuePointer obj = engine->newObject(); for (auto key : map.keys()) { - obj.setProperty(key, qVectorScriptableMaterialLayerToScriptValue(engine, map[key])); + obj->setProperty(key, qVectorScriptableMaterialLayerToScriptValue(engine, map[key])); } return obj; } - void multiMaterialMapFromScriptValue(const QScriptValue& map, scriptable::MultiMaterialMap& result) { - // No need to convert from QScriptValue to MultiMaterialMap + void multiMaterialMapFromScriptValue(const ScriptValuePointer& map, scriptable::MultiMaterialMap& result) { + // No need to convert from ScriptValuePointer to MultiMaterialMap } - template int registerDebugEnum(QScriptEngine* engine, const DebugEnums& debugEnums) { + template int registerDebugEnum(ScriptEngine* engine, const DebugEnums& debugEnums) { static const DebugEnums& instance = debugEnums; - return qScriptRegisterMetaType( + return scriptRegisterMetaType( engine, - [](QScriptEngine* engine, const T& topology) -> QScriptValue { - return instance.value(topology); + [](ScriptEngine* engine, const T& topology) -> ScriptValuePointer { + return engine->newValue(instance.value(topology)); }, - [](const QScriptValue& value, T& topology) { - topology = instance.key(value.toString()); + [](const ScriptValuePointer& value, T& topology) { + topology = instance.key(value->toString()); } ); } } -void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) { - qScriptRegisterSequenceMetaType>(engine); +void GraphicsScriptingInterface::registerMetaTypes(ScriptEngine* engine) { + scriptRegisterSequenceMetaType>(engine); scriptable::registerQPointerMetaType(engine); scriptable::registerQPointerMetaType(engine); @@ -677,10 +678,10 @@ void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) { scriptable::registerDebugEnum(engine, gpu::SEMANTICS); scriptable::registerDebugEnum(engine, gpu::DIMENSIONS); - qScriptRegisterMetaType(engine, scriptable::scriptableMaterialToScriptValue, scriptable::scriptableMaterialFromScriptValue); - qScriptRegisterMetaType(engine, scriptable::scriptableMaterialLayerToScriptValue, scriptable::scriptableMaterialLayerFromScriptValue); - qScriptRegisterMetaType(engine, scriptable::qVectorScriptableMaterialLayerToScriptValue, scriptable::qVectorScriptableMaterialLayerFromScriptValue); - qScriptRegisterMetaType(engine, scriptable::multiMaterialMapToScriptValue, scriptable::multiMaterialMapFromScriptValue); + scriptRegisterMetaType(engine, scriptable::scriptableMaterialToScriptValue, scriptable::scriptableMaterialFromScriptValue); + scriptRegisterMetaType(engine, scriptable::scriptableMaterialLayerToScriptValue, scriptable::scriptableMaterialLayerFromScriptValue); + scriptRegisterMetaType(engine, scriptable::qVectorScriptableMaterialLayerToScriptValue, scriptable::qVectorScriptableMaterialLayerFromScriptValue); + scriptRegisterMetaType(engine, scriptable::multiMaterialMapToScriptValue, scriptable::multiMaterialMapFromScriptValue); Q_UNUSED(metaTypeIds); } diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h index 0f24ae84613..0a42b6c5144 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h @@ -11,16 +11,18 @@ #ifndef hifi_GraphicsScriptingInterface_h #define hifi_GraphicsScriptingInterface_h +#include #include #include -#include -#include - #include "ScriptableMesh.h" #include #include "RegisteredMetaTypes.h" +#include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The Graphics API enables you to access and manipulate avatar, entity, and overlay models in the rendered scene. @@ -34,11 +36,11 @@ * @hifi-avatar */ -class GraphicsScriptingInterface : public QObject, public QScriptable, public Dependency { +class GraphicsScriptingInterface : public QObject, public Scriptable, public Dependency { Q_OBJECT public: - static void registerMetaTypes(QScriptEngine* engine); + static void registerMetaTypes(ScriptEngine* engine); GraphicsScriptingInterface(QObject* parent = nullptr); public slots: @@ -149,7 +151,7 @@ public slots: }; namespace scriptable { - QScriptValue scriptableMaterialToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterial &material); + ScriptValuePointer scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material); }; Q_DECLARE_METATYPE(NestableType) diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp index 92dddc953e7..b5671655b36 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp @@ -7,11 +7,12 @@ #include "GraphicsScriptingUtil.h" -#include - #include #include #include +#include "ScriptContext.h" +#include "ScriptEngine.h" +#include "ScriptValue.h" using buffer_helpers::glmVecToVariant; @@ -77,27 +78,27 @@ QVariant toVariant(const gpu::Element& element) { }; } -QScriptValue jsBindCallback(QScriptValue value) { - if (value.isObject() && value.property("callback").isFunction()) { +ScriptValuePointer jsBindCallback(ScriptValuePointer value) { + if (value->isObject() && value->property("callback")->isFunction()) { // value is already a bound callback return value; } - auto engine = value.engine(); + auto engine = value->engine(); auto context = engine ? engine->currentContext() : nullptr; auto length = context ? context->argumentCount() : 0; - QScriptValue scope = context ? context->thisObject() : QScriptValue::NullValue; - QScriptValue method; + ScriptValuePointer scope = context ? context->thisObject() : engine->nullValue(); + ScriptValuePointer method; #ifdef SCRIPTABLE_MESH_DEBUG qCInfo(graphics_scripting) << "jsBindCallback" << engine << length << scope.toQObject() << method.toString(); #endif // find position in the incoming JS Function.arguments array (so we can test for the two-argument case) for (int i = 0; context && i < length; i++) { - if (context->argument(i).strictlyEquals(value)) { + if (context->argument(i)->strictlyEquals(value)) { method = context->argument(i+1); } } - if (method.isFunction() || method.isString()) { + if (method->isFunction() || method->isString()) { // interpret as `API.func(..., scope, function callback(){})` or `API.func(..., scope, "methodName")` scope = value; } else { @@ -111,9 +112,9 @@ QScriptValue jsBindCallback(QScriptValue value) { } template -T this_qobject_cast(QScriptEngine* engine) { +T this_qobject_cast(ScriptEngine* engine) { auto context = engine ? engine->currentContext() : nullptr; - return qscriptvalue_cast(context ? context->thisObject() : QScriptValue::NullValue); + return scriptvalue_cast(context ? context->thisObject() : ScriptValuePointer::NullValue); } QString toDebugString(QObject* tmp) { QString s; diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h index 1ca62277ff5..ec979045529 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h @@ -1,8 +1,7 @@ #pragma once -#include -#include #include +#include #include #include #include @@ -10,6 +9,10 @@ #include #include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + class Extents; class AABox; namespace gpu { @@ -24,15 +27,15 @@ namespace scriptable { QVariant toVariant(const glm::mat4& mat4); // helper that automatically resolves Qt-signal-like scoped callbacks - // ... C++ side: `void MyClass::asyncMethod(..., QScriptValue callback)` + // ... C++ side: `void MyClass::asyncMethod(..., ScriptValuePointer callback)` // ... JS side: // * `API.asyncMethod(..., function(){})` // * `API.asyncMethod(..., scope, function(){})` // * `API.asyncMethod(..., scope, "methodName")` - QScriptValue jsBindCallback(QScriptValue callback); + ScriptValuePointer jsBindCallback(ScriptValuePointer callback); // cast engine->thisObject() => C++ class instance - template T this_qobject_cast(QScriptEngine* engine); + template T this_qobject_cast(ScriptEngine* engine); QString toDebugString(QObject* tmp); template QString toDebugString(std::shared_ptr tmp); diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp index 3de5119fa76..2535e220974 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp @@ -7,17 +7,19 @@ #include "ScriptableMesh.h" -#include +#include #include #include #include -#include #include #include #include #include +#include +#include +#include #include "Forward.h" #include "ScriptableMeshPart.h" @@ -27,7 +29,7 @@ // #define SCRIPTABLE_MESH_DEBUG 1 scriptable::ScriptableMesh::ScriptableMesh(const ScriptableMeshBase& other) - : ScriptableMeshBase(other), QScriptable() { + : ScriptableMeshBase(other), Scriptable() { auto mesh = getMeshPointer(); QString name = mesh ? QString::fromStdString(mesh->modelName) : ""; if (name.isEmpty()) { @@ -264,7 +266,7 @@ bool scriptable::ScriptableMesh::setVertexProperty(glm::uint32 vertexIndex, cons * @param {number} index - The vertex index. * @param {object} properties - The properties of the mesh, per {@link GraphicsMesh}. */ -glm::uint32 scriptable::ScriptableMesh::forEachVertex(QScriptValue _callback) { +glm::uint32 scriptable::ScriptableMesh::forEachVertex(ScriptValuePointer _callback) { auto mesh = getMeshPointer(); if (!mesh) { return 0; @@ -272,16 +274,16 @@ glm::uint32 scriptable::ScriptableMesh::forEachVertex(QScriptValue _callback) { auto scopedHandler = jsBindCallback(_callback); // destructure so we can still invoke callback scoped, but with a custom signature (obj, i, jsMesh) - auto scope = scopedHandler.property("scope"); - auto callback = scopedHandler.property("callback"); - auto js = engine() ? engine() : scopedHandler.engine(); // cache value to avoid resolving each iteration + auto scope = scopedHandler->property("scope"); + auto callback = scopedHandler->property("callback"); + auto js = engine() ? engine() : scopedHandler->engine(); // cache value to avoid resolving each iteration if (!js) { return 0; } - auto meshPart = js ? js->toScriptValue(getSelf()) : QScriptValue::NullValue; + auto meshPart = js ? js->toScriptValue(getSelf()) : js->nullValue(); int numProcessed = 0; buffer_helpers::mesh::forEachVertex(mesh, [&](glm::uint32 index, const QVariantMap& values) { - auto result = callback.call(scope, { js->toScriptValue(values), index, meshPart }); + auto result = callback->call(scope, { js->toScriptValue(values), js->newValue(index), meshPart }); if (js->hasUncaughtException()) { js->currentContext()->throwValue(js->uncaughtException()); return false; @@ -302,7 +304,7 @@ glm::uint32 scriptable::ScriptableMesh::forEachVertex(QScriptValue _callback) { * @returns {Object|boolean} The attribute values to update the vertex with, or * false to not update the vertex. */ -glm::uint32 scriptable::ScriptableMesh::updateVertexAttributes(QScriptValue _callback) { +glm::uint32 scriptable::ScriptableMesh::updateVertexAttributes(ScriptValuePointer _callback) { auto mesh = getMeshPointer(); if (!mesh) { return 0; @@ -310,34 +312,34 @@ glm::uint32 scriptable::ScriptableMesh::updateVertexAttributes(QScriptValue _cal auto scopedHandler = jsBindCallback(_callback); // destructure so we can still invoke callback scoped, but with a custom signature (obj, i, jsMesh) - auto scope = scopedHandler.property("scope"); - auto callback = scopedHandler.property("callback"); - auto js = engine() ? engine() : scopedHandler.engine(); // cache value to avoid resolving each iteration + auto scope = scopedHandler->property("scope"); + auto callback = scopedHandler->property("callback"); + auto js = engine() ? engine() : scopedHandler->engine(); // cache value to avoid resolving each iteration if (!js) { return 0; } - auto meshPart = js ? js->toScriptValue(getSelf()) : QScriptValue::NullValue; + auto meshPart = js ? js->toScriptValue(getSelf()) : js->nullValue(); int numProcessed = 0; auto attributeViews = buffer_helpers::mesh::getAllBufferViews(mesh); buffer_helpers::mesh::forEachVertex(mesh, [&](glm::uint32 index, const QVariantMap& values) { auto obj = js->toScriptValue(values); - auto result = callback.call(scope, { obj, index, meshPart }); + auto result = callback->call(scope, { obj, js->newValue(index), meshPart }); if (js->hasUncaughtException()) { js->currentContext()->throwValue(js->uncaughtException()); return false; } - if (result.isBool() && !result.toBool()) { + if (result->isBool() && !result->toBool()) { // bail without modifying data if user explicitly returns false return true; } - if (result.isObject() && !result.strictlyEquals(obj)) { + if (result->isObject() && !result->strictlyEquals(obj)) { // user returned a new object (ie: instead of modifying input properties) obj = result; } for (const auto& a : attributeViews) { - const auto& attribute = obj.property(a.first); - if (attribute.isValid()) { - buffer_helpers::setValue(a.second, index, attribute.toVariant()); + const auto& attribute = obj->property(a.first); + if (attribute->isValid()) { + buffer_helpers::setValue(a.second, index, attribute->toVariant()); } } numProcessed++; diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h index 0e7eecc03b9..0c431bda305 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h @@ -20,12 +20,15 @@ #include #include #include -#include -#include +#include #include "GraphicsScriptingUtil.h" #include +#include + +class ScriptValue; +using ScriptValuePointer = QSharedPointer; namespace scriptable { /**jsdoc @@ -65,7 +68,7 @@ namespace scriptable { * @borrows GraphicsMesh.getVertextAttributes as getVertextAttributes * @borrows GraphicsMesh.setVertextAttributes as setVertextAttributes */ - class ScriptableMesh : public ScriptableMeshBase, QScriptable { + class ScriptableMesh : public ScriptableMeshBase, Scriptable { Q_OBJECT public: Q_PROPERTY(glm::uint32 numParts READ getNumParts) @@ -83,11 +86,11 @@ namespace scriptable { operator const ScriptableMeshBase*() const { return (qobject_cast(this)); } ScriptableMesh(WeakModelProviderPointer provider, ScriptableModelBasePointer model, MeshPointer mesh, QObject* parent) - : ScriptableMeshBase(provider, model, mesh, parent), QScriptable() { strongMesh = mesh; } + : ScriptableMeshBase(provider, model, mesh, parent), Scriptable() { strongMesh = mesh; } ScriptableMesh(MeshPointer mesh, QObject* parent) - : ScriptableMeshBase(WeakModelProviderPointer(), nullptr, mesh, parent), QScriptable() { strongMesh = mesh; } + : ScriptableMeshBase(WeakModelProviderPointer(), nullptr, mesh, parent), Scriptable() { strongMesh = mesh; } ScriptableMesh(const ScriptableMeshBase& other); - ScriptableMesh(const ScriptableMesh& other) : ScriptableMeshBase(other), QScriptable() {}; + ScriptableMesh(const ScriptableMesh& other) : ScriptableMeshBase(other), Scriptable() {}; virtual ~ScriptableMesh(); const scriptable::MeshPointer getOwnedMeshPointer() const { return strongMesh; } @@ -224,7 +227,7 @@ namespace scriptable { */ scriptable::ScriptableMeshPointer cloneMesh(); - // QScriptEngine-specific wrappers + // ScriptEngine-specific wrappers /**jsdoc * Updates vertex attributes by calling a function for each vertex. The function can return modified attributes to @@ -233,7 +236,7 @@ namespace scriptable { * @param {GraphicsMesh~updateVertexAttributesCallback} callback - The function to call for each vertex. * @returns {number} The number of vertices the callback was called for. */ - glm::uint32 updateVertexAttributes(QScriptValue callback); + glm::uint32 updateVertexAttributes(ScriptValuePointer callback); /**jsdoc * Calls a function for each vertex. @@ -241,7 +244,7 @@ namespace scriptable { * @param {GraphicsMesh~forEachVertexCallback} callback - The function to call for each vertex. * @returns {number} The number of vertices the callback was called for. */ - glm::uint32 forEachVertex(QScriptValue callback); + glm::uint32 forEachVertex(ScriptValuePointer callback); /**jsdoc * Checks if an index is valid and, optionally, that vertex has a particular attribute. diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp index f14c63b5606..d12dc0c60cc 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp @@ -11,8 +11,7 @@ #include #include -#include -#include +#include #include #include #include @@ -78,12 +77,12 @@ QVariantList scriptable::ScriptableMeshPart::queryVertexAttributes(QVariant sele return parentMesh->queryVertexAttributes(selector); } -glm::uint32 scriptable::ScriptableMeshPart::forEachVertex(QScriptValue _callback) { +glm::uint32 scriptable::ScriptableMeshPart::forEachVertex(ScriptValuePointer _callback) { // TODO: limit to vertices within the part's indexed range? return isValid() ? parentMesh->forEachVertex(_callback) : 0; } -glm::uint32 scriptable::ScriptableMeshPart::updateVertexAttributes(QScriptValue _callback) { +glm::uint32 scriptable::ScriptableMeshPart::updateVertexAttributes(ScriptValuePointer _callback) { // TODO: limit to vertices within the part's indexed range? return isValid() ? parentMesh->updateVertexAttributes(_callback) : 0; } diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h index 878b239f3d2..0d65d4f609f 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h @@ -7,7 +7,13 @@ #pragma once +#include + #include "ScriptableMesh.h" +#include + +class ScriptValue; +using ScriptValuePointer = QSharedPointer; namespace scriptable { /**jsdoc @@ -55,7 +61,7 @@ namespace scriptable { * @borrows GraphicsMesh.getVertexAttributes as getVertextAttributes * @borrows GraphicsMesh.setVertexAttributes as setVertextAttributes */ - class ScriptableMeshPart : public QObject, QScriptable { + class ScriptableMeshPart : public QObject, Scriptable { Q_OBJECT Q_PROPERTY(bool valid READ isValid) Q_PROPERTY(glm::uint32 partIndex MEMBER partIndex CONSTANT) @@ -78,7 +84,7 @@ namespace scriptable { public: ScriptableMeshPart(scriptable::ScriptableMeshPointer parentMesh, int partIndex); ScriptableMeshPart& operator=(const ScriptableMeshPart& view) { parentMesh=view.parentMesh; return *this; }; - ScriptableMeshPart(const ScriptableMeshPart& other) : QObject(other.parent()), QScriptable(), parentMesh(other.parentMesh), partIndex(other.partIndex) {} + ScriptableMeshPart(const ScriptableMeshPart& other) : QObject(other.parent()), Scriptable(), parentMesh(other.parentMesh), partIndex(other.partIndex) {} bool isValid() const { auto mesh = getMeshPointer(); return mesh && partIndex < mesh->getNumParts(); } public slots: @@ -273,7 +279,7 @@ namespace scriptable { QString toOBJ(); - // QScriptEngine-specific wrappers + // ScriptEngine-specific wrappers /**jsdoc * Updates vertex attributes by calling a function for each vertex in the whole mesh (i.e., the parent and @@ -282,7 +288,7 @@ namespace scriptable { * @param {GraphicsMesh~updateVertexAttributesCallback} callback - The function to call for each vertex. * @returns {number} The number of vertices the callback was called for. */ - glm::uint32 updateVertexAttributes(QScriptValue callback); + glm::uint32 updateVertexAttributes(ScriptValuePointer callback); /**jsdoc * Calls a function for each vertex in the whole mesh (i.e., parent and mesh parts). @@ -290,7 +296,7 @@ namespace scriptable { * @param {GraphicsMesh~forEachVertexCallback} callback - The function to call for each vertex. * @returns {number} The number of vertices the callback was called for. */ - glm::uint32 forEachVertex(QScriptValue callback); + glm::uint32 forEachVertex(ScriptValuePointer callback); /**jsdoc * Checks if an index is valid and, optionally, that vertex has a particular attribute. diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp index 28cd49e7c47..2885a9a5de3 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -10,7 +10,7 @@ #include "ScriptableModel.h" -#include +#include #include "GraphicsScriptingUtil.h" #include "ScriptableMesh.h" @@ -262,7 +262,7 @@ scriptable::ScriptableMeshes scriptable::ScriptableModel::getMeshes() { } #if 0 -glm::uint32 scriptable::ScriptableModel::forEachVertexAttribute(QScriptValue callback) { +glm::uint32 scriptable::ScriptableModel::forEachVertexAttribute(ScriptValuePointer callback) { glm::uint32 result = 0; scriptable::ScriptableMeshes in = getMeshes(); if (in.size()) { diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index a6f135c3214..f64653135c3 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -10,8 +10,6 @@ #include "Forward.h" #include "GraphicsScriptingUtil.h" -class QScriptValue; - namespace scriptable { using ScriptableMeshes = QVector; diff --git a/libraries/model-networking/src/model-networking/SimpleMeshProxy.h b/libraries/model-networking/src/model-networking/SimpleMeshProxy.h index 9282557a4fb..58c55a5e1f9 100644 --- a/libraries/model-networking/src/model-networking/SimpleMeshProxy.h +++ b/libraries/model-networking/src/model-networking/SimpleMeshProxy.h @@ -12,10 +12,6 @@ #ifndef hifi_SimpleMeshProxy_h #define hifi_SimpleMeshProxy_h -#include -#include -#include - #include class SimpleMeshProxy : public MeshProxy { diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 9f63f2cb00f..09b0e182de2 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME networking) setup_hifi_library(Network) link_hifi_libraries(shared platform) +include_hifi_library_headers(script-engine) target_openssl() target_tbb() diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index bbd743cf955..3df3fce6cd3 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/libraries/networking/src/BaseAssetScriptingInterface.h b/libraries/networking/src/BaseAssetScriptingInterface.h index 7d118e1979d..18ba8c294a4 100644 --- a/libraries/networking/src/BaseAssetScriptingInterface.h +++ b/libraries/networking/src/BaseAssetScriptingInterface.h @@ -9,7 +9,7 @@ // // BaseAssetScriptingInterface contains the engine-agnostic support code that can be used from -// both QML JS and QScriptEngine JS engine implementations +// both QML JS and ScriptEngine JS engine implementations #ifndef hifi_BaseAssetScriptingInterface_h #define hifi_BaseAssetScriptingInterface_h diff --git a/libraries/networking/src/LocationScriptingInterface.cpp b/libraries/networking/src/LocationScriptingInterface.cpp index 39845558a8a..23884cab1e3 100644 --- a/libraries/networking/src/LocationScriptingInterface.cpp +++ b/libraries/networking/src/LocationScriptingInterface.cpp @@ -12,22 +12,25 @@ #include "LocationScriptingInterface.h" #include "AddressManager.h" +#include +#include +#include LocationScriptingInterface* LocationScriptingInterface::getInstance() { static LocationScriptingInterface sharedInstance; return &sharedInstance; } -QScriptValue LocationScriptingInterface::locationGetter(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer LocationScriptingInterface::locationGetter(ScriptContext* context, ScriptEngine* engine) { return engine->newQObject(DependencyManager::get().data()); } -QScriptValue LocationScriptingInterface::locationSetter(QScriptContext* context, QScriptEngine* engine) { - const QVariant& argumentVariant = context->argument(0).toVariant(); +ScriptValuePointer LocationScriptingInterface::locationSetter(ScriptContext* context, ScriptEngine* engine) { + const QVariant& argumentVariant = context->argument(0)->toVariant(); // just try and convert the argument to a string, should be a hifi:// address QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", Q_ARG(const QString&, argumentVariant.toString())); - return QScriptValue::UndefinedValue; + return engine->undefinedValue(); } diff --git a/libraries/networking/src/LocationScriptingInterface.h b/libraries/networking/src/LocationScriptingInterface.h index f1086ffa600..0fc6b6ec724 100644 --- a/libraries/networking/src/LocationScriptingInterface.h +++ b/libraries/networking/src/LocationScriptingInterface.h @@ -12,15 +12,20 @@ #ifndef hifi_LocationScriptingInterface_h #define hifi_LocationScriptingInterface_h -#include +#include + +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class LocationScriptingInterface : public QObject { Q_OBJECT public: static LocationScriptingInterface* getInstance(); - static QScriptValue locationGetter(QScriptContext* context, QScriptEngine* engine); - static QScriptValue locationSetter(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer locationGetter(ScriptContext* context, ScriptEngine* engine); + static ScriptValuePointer locationSetter(ScriptContext* context, ScriptEngine* engine); private: LocationScriptingInterface() {}; }; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 73af38fd369..125640d0b9d 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -28,8 +28,6 @@ #include #include -#include - #include #include "ResourceManager.h" @@ -234,7 +232,7 @@ protected slots: void updateTotalSize(const qint64& deltaSize); - // Prefetches a resource to be held by the QScriptEngine. + // Prefetches a resource to be held by the ScriptEngine. // Left as a protected member so subclasses can overload prefetch // and delegate to it (see TextureCache::prefetch(const QUrl&, int). ScriptableResource* prefetch(const QUrl& url, void* extra, size_t extraHash); @@ -252,10 +250,10 @@ private slots: void clearATPAssets(); protected: - // Prefetches a resource to be held by the QScriptEngine. + // Prefetches a resource to be held by the ScriptEngine. // Pointers created through this method should be owned by the caller, - // which should be a QScriptEngine with ScriptableResource registered, so that - // the QScriptEngine will delete the pointer when it is garbage collected. + // which should be a ScriptEngine with ScriptableResource registered, so that + // the ScriptEngine will delete the pointer when it is garbage collected. // JSDoc is provided on more general function signature. Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url) { return prefetch(url, nullptr, std::numeric_limits::max()); } diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index ad4900e4ba1..2d6bbe27b3d 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -14,5 +14,6 @@ include_hifi_library_headers(gpu) include_hifi_library_headers(hfm) include_hifi_library_headers(model-serializers) include_hifi_library_headers(graphics) +include_hifi_library_headers(script-engine) target_bullet() diff --git a/libraries/pointers/CMakeLists.txt b/libraries/pointers/CMakeLists.txt index e33c76e2495..184e9ae5549 100644 --- a/libraries/pointers/CMakeLists.txt +++ b/libraries/pointers/CMakeLists.txt @@ -2,4 +2,4 @@ set(TARGET_NAME pointers) setup_hifi_library() GroupSources(src) link_hifi_libraries(shared controllers) - +include_hifi_library_headers(script-engine) diff --git a/libraries/recording/CMakeLists.txt b/libraries/recording/CMakeLists.txt index b42a4018f8c..5821688eb06 100644 --- a/libraries/recording/CMakeLists.txt +++ b/libraries/recording/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME recording) # set a default root dir for each of our optional externals if it was not passed -setup_hifi_library(Script) +setup_hifi_library() # use setup_hifi_library macro to setup our project and link appropriate Qt modules link_hifi_libraries(shared networking) diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 4c444bcd155..fb825d4ecfd 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME render-utils) # pull in the resources.qrc file qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") -setup_hifi_library(Gui Network Qml Quick Script) +setup_hifi_library(Gui Network Qml Quick) link_hifi_libraries(shared task ktx gpu shaders graphics graphics-scripting material-networking model-networking render animation model-serializers image procedural) include_hifi_library_headers(audio) include_hifi_library_headers(networking) diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 930f9422603..bf8cef81f33 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -45,7 +45,6 @@ #define SKIN_DQ class AbstractViewStateInterface; -class QScriptEngine; class ViewFrustum; diff --git a/libraries/script-engine-qtscript/CMakeLists.txt b/libraries/script-engine-qtscript/CMakeLists.txt new file mode 100644 index 00000000000..65a80d0ff34 --- /dev/null +++ b/libraries/script-engine-qtscript/CMakeLists.txt @@ -0,0 +1,10 @@ +set(TARGET_NAME script-engine-qtscript) +# FIXME Move undo scripting interface to application and remove Widgets +setup_hifi_library(Gui Script ScriptTools) + +link_hifi_libraries() +include_hifi_library_headers(animation) +include_hifi_library_headers(entities) +include_hifi_library_headers(networking) +include_hifi_library_headers(shared) +include_hifi_library_headers(script-engine) \ No newline at end of file diff --git a/libraries/script-engine/src/ArrayBufferClass.h b/libraries/script-engine-qtscript/src/ArrayBufferClass.h similarity index 95% rename from libraries/script-engine/src/ArrayBufferClass.h rename to libraries/script-engine-qtscript/src/ArrayBufferClass.h index 3255ab30e70..3048ce15c61 100644 --- a/libraries/script-engine/src/ArrayBufferClass.h +++ b/libraries/script-engine-qtscript/src/ArrayBufferClass.h @@ -21,12 +21,12 @@ #include #include -class ScriptEngine; +class ScriptEngineQtScript; class ArrayBufferClass : public QObject, public QScriptClass { Q_OBJECT public: - ArrayBufferClass(ScriptEngine* scriptEngine); + ArrayBufferClass(ScriptEngineQtScript* scriptEngine); QScriptValue newInstance(qint32 size); QScriptValue newInstance(const QByteArray& ba); diff --git a/libraries/script-engine/src/ArrayBufferPrototype.cpp b/libraries/script-engine-qtscript/src/ArrayBufferPrototype.cpp similarity index 98% rename from libraries/script-engine/src/ArrayBufferPrototype.cpp rename to libraries/script-engine-qtscript/src/ArrayBufferPrototype.cpp index d75482aa2e6..2523a47e27e 100644 --- a/libraries/script-engine/src/ArrayBufferPrototype.cpp +++ b/libraries/script-engine-qtscript/src/ArrayBufferPrototype.cpp @@ -13,8 +13,8 @@ #include -#include -#include +#include +#include #include "ArrayBufferClass.h" diff --git a/libraries/script-engine/src/ArrayBufferPrototype.h b/libraries/script-engine-qtscript/src/ArrayBufferPrototype.h similarity index 100% rename from libraries/script-engine/src/ArrayBufferPrototype.h rename to libraries/script-engine-qtscript/src/ArrayBufferPrototype.h diff --git a/libraries/script-engine/src/ArrayBufferViewClass.cpp b/libraries/script-engine-qtscript/src/ArrayBufferViewClass.cpp similarity index 92% rename from libraries/script-engine/src/ArrayBufferViewClass.cpp rename to libraries/script-engine-qtscript/src/ArrayBufferViewClass.cpp index cf776ed8340..fa1c114b5be 100644 --- a/libraries/script-engine/src/ArrayBufferViewClass.cpp +++ b/libraries/script-engine-qtscript/src/ArrayBufferViewClass.cpp @@ -10,11 +10,12 @@ // #include "ArrayBufferViewClass.h" +#include "ScriptEngineQtScript.h" Q_DECLARE_METATYPE(QByteArray*) -ArrayBufferViewClass::ArrayBufferViewClass(ScriptEngine* scriptEngine) : -QObject(scriptEngine), +ArrayBufferViewClass::ArrayBufferViewClass(ScriptEngineQtScript* scriptEngine) : + QObject(scriptEngine), QScriptClass(scriptEngine), _scriptEngine(scriptEngine) { // Save string handles for quick lookup diff --git a/libraries/script-engine/src/ArrayBufferViewClass.h b/libraries/script-engine-qtscript/src/ArrayBufferViewClass.h similarity index 88% rename from libraries/script-engine/src/ArrayBufferViewClass.h rename to libraries/script-engine-qtscript/src/ArrayBufferViewClass.h index a1f7f8245fa..120592b099c 100644 --- a/libraries/script-engine/src/ArrayBufferViewClass.h +++ b/libraries/script-engine-qtscript/src/ArrayBufferViewClass.h @@ -20,7 +20,7 @@ #include #include -#include "ScriptEngine.h" +class ScriptEngineQtScript; static const QString BUFFER_PROPERTY_NAME = "buffer"; static const QString BYTE_OFFSET_PROPERTY_NAME = "byteOffset"; @@ -29,9 +29,9 @@ static const QString BYTE_LENGTH_PROPERTY_NAME = "byteLength"; class ArrayBufferViewClass : public QObject, public QScriptClass { Q_OBJECT public: - ArrayBufferViewClass(ScriptEngine* scriptEngine); + ArrayBufferViewClass(ScriptEngineQtScript* scriptEngine); - ScriptEngine* getScriptEngine() { return _scriptEngine; } + ScriptEngineQtScript* getScriptEngine() { return _scriptEngine; } virtual QueryFlags queryProperty(const QScriptValue& object, const QScriptString& name, @@ -46,7 +46,7 @@ class ArrayBufferViewClass : public QObject, public QScriptClass { QScriptString _byteOffsetName; QScriptString _byteLengthName; - ScriptEngine* _scriptEngine; + ScriptEngineQtScript* _scriptEngine; }; #endif // hifi_ArrayBufferViewClass_h diff --git a/libraries/shared/src/BaseScriptEngine.cpp b/libraries/script-engine-qtscript/src/BaseScriptEngine.cpp similarity index 88% rename from libraries/shared/src/BaseScriptEngine.cpp rename to libraries/script-engine-qtscript/src/BaseScriptEngine.cpp index 22ae01d72f0..6e815174735 100644 --- a/libraries/shared/src/BaseScriptEngine.cpp +++ b/libraries/script-engine-qtscript/src/BaseScriptEngine.cpp @@ -21,9 +21,6 @@ #include "Profile.h" -const QString BaseScriptEngine::SCRIPT_EXCEPTION_FORMAT { "[%0] %1 in %2:%3" }; -const QString BaseScriptEngine::SCRIPT_BACKTRACE_SEP { "\n " }; - bool BaseScriptEngine::IS_THREADSAFE_INVOCATION(const QThread *thread, const QString& method) { if (QThread::currentThread() == thread) { return true; @@ -84,7 +81,7 @@ QScriptValue BaseScriptEngine::lintScript(const QString& sourceCode, const QStri err.setProperty("fileName", fileName); err.setProperty("lineNumber", syntaxCheck.errorLineNumber()); err.setProperty("expressionBeginOffset", syntaxCheck.errorColumnNumber()); - err.setProperty("stack", currentContext()->backtrace().join(SCRIPT_BACKTRACE_SEP)); + err.setProperty("stack", currentContext()->backtrace().join(ScriptManager::SCRIPT_BACKTRACE_SEP)); { const auto error = syntaxCheck.errorMessage(); const auto line = QString::number(syntaxCheck.errorLineNumber()); @@ -120,7 +117,7 @@ QScriptValue BaseScriptEngine::cloneUncaughtException(const QString& extraDetail auto backtrace = uncaughtExceptionBacktrace(); if (backtrace.isEmpty()) { // fallback to the error object - backtrace = exception.property("stack").toString().split(SCRIPT_BACKTRACE_SEP); + backtrace = exception.property("stack").toString().split(ScriptManager::SCRIPT_BACKTRACE_SEP); } // the ad hoc "detail" property can be used now to embed additional clues auto detail = exception.property("detail").toString(); @@ -150,7 +147,7 @@ QScriptValue BaseScriptEngine::cloneUncaughtException(const QString& extraDetail err.setProperty("fileName", fileName); err.setProperty("lineNumber", lineNumber ); err.setProperty("detail", detail); - err.setProperty("stack", backtrace.join(SCRIPT_BACKTRACE_SEP)); + err.setProperty("stack", backtrace.join(ScriptManager::SCRIPT_BACKTRACE_SEP)); #ifdef DEBUG_JS_EXCEPTIONS err.setProperty("_fileName", exception.property("fileName").toString()); @@ -160,38 +157,6 @@ QScriptValue BaseScriptEngine::cloneUncaughtException(const QString& extraDetail return err; } -QString BaseScriptEngine::formatException(const QScriptValue& exception, bool includeExtendedDetails) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return QString(); - } - QString note { "UncaughtException" }; - QString result; - - if (!exception.isObject()) { - return result; - } - const auto message = exception.toString(); - const auto fileName = exception.property("fileName").toString(); - const auto lineNumber = exception.property("lineNumber").toString(); - const auto stacktrace = exception.property("stack").toString(); - - if (includeExtendedDetails) { - // Display additional exception / troubleshooting hints that can be added via the custom Error .detail property - // Example difference: - // [UncaughtExceptions] Error: Can't find variable: foobar in atp:/myentity.js\n... - // [UncaughtException (construct {1eb5d3fa-23b1-411c-af83-163af7220e3f})] Error: Can't find variable: foobar in atp:/myentity.js\n... - if (exception.property("detail").isValid()) { - note += " " + exception.property("detail").toString(); - } - } - - result = QString(SCRIPT_EXCEPTION_FORMAT).arg(note, message, fileName, lineNumber); - if (!stacktrace.isEmpty()) { - result += QString("\n[Backtrace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace); - } - return result; -} - bool BaseScriptEngine::raiseException(const QScriptValue& exception) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return false; diff --git a/libraries/shared/src/BaseScriptEngine.h b/libraries/script-engine-qtscript/src/BaseScriptEngine.h similarity index 66% rename from libraries/shared/src/BaseScriptEngine.h rename to libraries/script-engine-qtscript/src/BaseScriptEngine.h index 443c7b05000..06493807e80 100644 --- a/libraries/shared/src/BaseScriptEngine.h +++ b/libraries/script-engine-qtscript/src/BaseScriptEngine.h @@ -16,16 +16,13 @@ #include #include -class ScriptEngine; -using ScriptEnginePointer = QSharedPointer; +class ScriptEngineQtScript; +using ScriptEngineQtScriptPointer = QSharedPointer; // common base class for extending QScriptEngine itself class BaseScriptEngine : public QScriptEngine, public QEnableSharedFromThis { Q_OBJECT public: - static const QString SCRIPT_EXCEPTION_FORMAT; - static const QString SCRIPT_BACKTRACE_SEP; - // threadsafe "unbound" version of QScriptEngine::nullValue() static const QScriptValue unboundNullValue() { return QScriptValue(0, QScriptValue::NullValue); } @@ -50,15 +47,6 @@ class BaseScriptEngine : public QScriptEngine, public QEnableSharedFromThisReport the details of an unhandled exception. - * Script.unhandledException.connect(function (exception) { - * print("Unhandled exception: " + JSON.stringify(exception)); - * }); - * var properties = JSON.parse("{ x: 1"); // Invalid JSON string. - */ - void unhandledException(const QScriptValue& exception); - protected: // like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues // even though the context/engine parameters are redundant in most cases, the function signature matches `newFunction` @@ -105,18 +80,6 @@ class BaseScriptEngine : public QScriptEngine, public QEnableSharedFromThisglobalObject(); // Save string handles for quick lookup diff --git a/libraries/script-engine/src/DataViewClass.h b/libraries/script-engine-qtscript/src/DataViewClass.h similarity index 93% rename from libraries/script-engine/src/DataViewClass.h rename to libraries/script-engine-qtscript/src/DataViewClass.h index 72c920a7273..8bdf9bba4a4 100644 --- a/libraries/script-engine/src/DataViewClass.h +++ b/libraries/script-engine-qtscript/src/DataViewClass.h @@ -17,7 +17,7 @@ class DataViewClass : public ArrayBufferViewClass { Q_OBJECT public: - DataViewClass(ScriptEngine* scriptEngine); + DataViewClass(ScriptEngineQtScript* scriptEngine); QScriptValue newInstance(QScriptValue buffer, quint32 byteOffset, quint32 byteLength); QString name() const override; diff --git a/libraries/script-engine/src/DataViewPrototype.cpp b/libraries/script-engine-qtscript/src/DataViewPrototype.cpp similarity index 99% rename from libraries/script-engine/src/DataViewPrototype.cpp rename to libraries/script-engine-qtscript/src/DataViewPrototype.cpp index ef757a5cb4d..ff540f5300a 100644 --- a/libraries/script-engine/src/DataViewPrototype.cpp +++ b/libraries/script-engine-qtscript/src/DataViewPrototype.cpp @@ -12,9 +12,12 @@ #include "DataViewPrototype.h" #include +#include #include +#include + #include "DataViewClass.h" Q_DECLARE_METATYPE(QByteArray*) diff --git a/libraries/script-engine/src/DataViewPrototype.h b/libraries/script-engine-qtscript/src/DataViewPrototype.h similarity index 100% rename from libraries/script-engine/src/DataViewPrototype.h rename to libraries/script-engine-qtscript/src/DataViewPrototype.h diff --git a/libraries/script-engine-qtscript/src/ScriptEngineQtScript.cpp b/libraries/script-engine-qtscript/src/ScriptEngineQtScript.cpp new file mode 100644 index 00000000000..ee5d0ec8a75 --- /dev/null +++ b/libraries/script-engine-qtscript/src/ScriptEngineQtScript.cpp @@ -0,0 +1,493 @@ +// +// ScriptEngineQtScript.cpp +// libraries/script-engine-qtscript/src +// +// Created by Brad Hefta-Gaub on 12/14/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptEngineQtScript.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +//#include +//#include +#include + +//#include "ArrayBufferViewClass.h" +//#include "AssetScriptingInterface.h" +//#include "BatchLoader.h" +//#include "BaseScriptEngine.h" +//#include "DataViewClass.h" +//#include "EventTypes.h" +//#include "FileScriptingInterface.h" // unzip project +//#include "MenuItemProperties.h" +//#include "ScriptAudioInjector.h" +//#include "ScriptAvatarData.h" +//#include "ScriptCache.h" +//#include "TypedArrays.h" +//#include "XMLHttpRequestClass.h" +//#include "WebSocketClass.h" +//#include "RecordingScriptingInterface.h" +//#include "ScriptEngines.h" +//#include "StackTestScriptingInterface.h" +//#include "ModelScriptingInterface.h" + +//#include + +//#include "../../midi/src/Midi.h" // FIXME why won't a simpler include work? +//#include "MIDIEvent.h" + +//#include "SettingHandle.h" +//#include +//#include +//#include + +static const int MAX_MODULE_ID_LENGTH { 4096 }; +static const int MAX_DEBUG_VALUE_LENGTH { 80 }; + +static const QScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = + QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects; +static const QScriptValue::PropertyFlags READONLY_PROP_FLAGS { QScriptValue::ReadOnly | QScriptValue::Undeletable }; +static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_PROP_FLAGS | QScriptValue::SkipInEnumeration }; + +static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; + +Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) +int functionSignatureMetaID = qRegisterMetaType(); + +int scriptEnginePointerMetaID = qRegisterMetaType(); + +static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { + // assemble the message by concatenating our arguments + QString message = ""; + for (int i = 0; i < context->argumentCount(); i++) { + if (i > 0) { + message += " "; + } + message += context->argument(i).toString(); + } + + // was this generated by a script engine? If we don't recognize it then send the message and exit + ScriptEngineQtScript* scriptEngine = qobject_cast(engine); + if (!scriptEngine) { + qCDebug(scriptengine_script, "%s", qUtf8Printable(message)); + return QScriptValue(); + } + + QString filename; + auto scriptManager = scriptEngine->manager(); + if (scriptManager) { + filename = scriptManager->getFilename(); + } + + // This message was sent by one of our script engines, let's try to see if we can find the source. + // Note that the first entry in the backtrace should be "print" and is somewhat useless to us + AbstractLoggerInterface* loggerInterface = AbstractLoggerInterface::get(); + if (loggerInterface && loggerInterface->showSourceDebugging()) { + QScriptContext* userContext = context; + while (userContext && QScriptContextInfo(userContext).functionType() == QScriptContextInfo::NativeFunction) { + userContext = userContext->parentContext(); + } + QString location; + if (userContext) { + QScriptContextInfo contextInfo(userContext); + QString fileName = contextInfo.fileName(); + int lineNumber = contextInfo.lineNumber(); + QString functionName = contextInfo.functionName(); + + location = functionName; + if (!fileName.isEmpty()) { + if (location.isEmpty()) { + location = fileName; + } else { + location = QString("%1 at %2").arg(location).arg(fileName); + } + } + if (lineNumber != -1) { + location = QString("%1:%2").arg(location).arg(lineNumber); + } + } + if (location.isEmpty()) { + location = filename; + } + + // give the script engine a chance to notify the system about this message + scriptEngine->print(message); + + // send the message to debug log + qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(location), qUtf8Printable(message)); + } else { + scriptEngine->print(message); + // prefix the script engine name to help disambiguate messages in the main debug log + qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(filename), qUtf8Printable(message)); + } + + return QScriptValue(); +} + +ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : + BaseScriptEngine(), + _manager(scriptManager), + _arrayBufferClass(new ArrayBufferClass(this)) +{ + if (_manager) { + connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { + if (Base::hasUncaughtException()) { + // the engine's uncaughtException() seems to produce much better stack traces here + emit _manager->unhandledException(Base::cloneUncaughtException("signalHandlerException")); + Base::clearExceptions(); + } else { + // ... but may not always be available -- so if needed we fallback to the passed exception + emit _manager->unhandledException(exception); + } + }, Qt::DirectConnection); + } + + setProcessEventsInterval(MSECS_PER_SECOND); +} + +bool ScriptEngineQtScript::isDebugMode() const { +#if defined(DEBUG) + return true; +#else + return false; +#endif +} + +ScriptEngineQtScript::~ScriptEngineQtScript() {} + +void ScriptEngineQtScript::disconnectNonEssentialSignals() { + disconnect(); + QThread* workerThread; + // Ensure the thread should be running, and does exist + if (_isRunning && _isThreaded && (workerThread = Base::thread())) { + connect(this, &QObject::destroyed, workerThread, &QThread::quit); + connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); + } +} + +void ScriptEngineQtScript::executeOnScriptThread(std::function function, const Qt::ConnectionType& type ) { + if (QThread::currentThread() != Base::thread()) { + QMetaObject::invokeMethod(this, "executeOnScriptThread", type, Q_ARG(std::function, function)); + return; + } + + function(); +} + +void ScriptEngineQtScript::registerValue(const QString& valueName, QScriptValue value) { + if (QThread::currentThread() != Base::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; +#endif + QMetaObject::invokeMethod(this, "registerValue", + Q_ARG(const QString&, valueName), + Q_ARG(QScriptValue, value)); + return; + } + + QStringList pathToValue = valueName.split("."); + int partsToGo = pathToValue.length(); + QScriptValue partObject = globalObject(); + + for (const auto& pathPart : pathToValue) { + partsToGo--; + if (!partObject.property(pathPart).isValid()) { + if (partsToGo > 0) { + //QObject *object = new QObject; + QScriptValue partValue = newArray(); //newQObject(object, QScriptEngine::ScriptOwnership); + partObject.setProperty(pathPart, partValue); + } else { + partObject.setProperty(pathPart, value); + } + } + partObject = partObject.property(pathPart); + } +} + +void ScriptEngineQtScript::registerGlobalObject(const QString& name, QObject* object) { + if (QThread::currentThread() != Base::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; +#endif + QMetaObject::invokeMethod(this, "registerGlobalObject", + Q_ARG(const QString&, name), + Q_ARG(QObject*, object)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; +#endif + + if (!Base::globalObject().property(name).isValid()) { + if (object) { + QScriptValue value = Base::newQObject(object, QScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); + Base::globalObject().setProperty(name, value); + } else { + Base::globalObject().setProperty(name, QScriptValue()); + } + } +} + +void ScriptEngineQtScript::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != Base::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; +#endif + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; +#endif + + QScriptValue scriptFun = Base::newFunction(functionSignature, numArguments); + Base::globalObject().setProperty(name, scriptFun); +} + +void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != Base::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; +#endif + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; +#endif + + QScriptValue object = Base::globalObject().property(parent); + if (object.isValid()) { + QScriptValue scriptFun = Base::newFunction(functionSignature, numArguments); + object.setProperty(name, scriptFun); + } +} + +void ScriptEngineQtScript::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, + QScriptEngine::FunctionSignature setter, const QString& parent) { + if (QThread::currentThread() != Base::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + " name:" << name << "parent:" << parent; +#endif + QMetaObject::invokeMethod(this, "registerGetterSetter", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, getter), + Q_ARG(QScriptEngine::FunctionSignature, setter), + Q_ARG(const QString&, parent)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; +#endif + + QScriptValue setterFunction = Base::newFunction(setter, 1); + QScriptValue getterFunction = Base::newFunction(getter); + + if (!parent.isNull() && !parent.isEmpty()) { + QScriptValue object = Base::globalObject().property(parent); + if (object.isValid()) { + object.setProperty(name, setterFunction, QScriptValue::PropertySetter); + object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); + } + } else { + Base::globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); + Base::globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); + } +} + +// this is not redundant -- the version in BaseScriptEngine is specifically not Q_INVOKABLE +QScriptValue ScriptEngineQtScript::evaluateInClosure(const QScriptValue& closure, const QScriptProgram& program) { + return BaseScriptEngine::evaluateInClosure(closure, program); +} + +QScriptValue ScriptEngineQtScript::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) { + QSharedPointer scriptEngines(_scriptEngines); + if (!scriptEngines || scriptEngines->isStopped()) { + return QScriptValue(); // bail early + } + + if (QThread::currentThread() != Base::thread()) { + QScriptValue result; +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; +#endif + BLOCKING_INVOKE_METHOD(this, "evaluate", + Q_RETURN_ARG(QScriptValue, result), + Q_ARG(const QString&, sourceCode), + Q_ARG(const QString&, fileName), + Q_ARG(int, lineNumber)); + return result; + } + + // Check syntax + auto syntaxError = Base::lintScript(sourceCode, fileName); + if (syntaxError.isError()) { + if (!Base::isEvaluating()) { + syntaxError.setProperty("detail", "evaluate"); + } + Base::raiseException(syntaxError); + Base::maybeEmitUncaughtException("lint"); + return syntaxError; + } + QScriptProgram program { sourceCode, fileName, lineNumber }; + if (program.isNull()) { + // can this happen? + auto err = Base::makeError("could not create QScriptProgram for " + fileName); + Base::raiseException(err); + Base::maybeEmitUncaughtException("compile"); + return err; + } + + QScriptValue result; + { + result = BaseScriptEngine::evaluate(program); + Base::maybeEmitUncaughtException("evaluate"); + } + return result; +} + +void ScriptEngineQtScript::updateMemoryCost(const qint64& deltaSize) { + if (deltaSize > 0) { + // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) + reportAdditionalMemoryCost(deltaSize); +#endif + } +} + +void ScriptEngineQtScript::print(const QString& message) { + QString filename; + auto scriptManager = manager(); + if (scriptManager) { + filename = scriptManager->getFilename(); + } + + emit printedMessage(message, filename); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ScriptEngine implementation +/* +ScriptValuePointer ScriptEngineQtScript::globalObject() const { + return Base::globalObject(); +} + +ScriptManager* ScriptEngineQtScript::manager() const { +} + +ScriptValuePointer ScriptEngineQtScript::newArray(uint length) { + return Base::newArray(length); +} + +ScriptValuePointer ScriptEngineQtScript::newArrayBuffer(const QByteArray& message) { + QScriptValue data = Base::newVariant(QVariant::fromValue(message)); + QScriptValue ctor = Base::globalObject().property("ArrayBuffer"); + auto array = qscriptvalue_cast(ctor.data()); + if (!array) { + return undefinedValue() + } + return Base::newObject(array, data); +} + +ScriptValuePointer ScriptEngineQtScript::newObject() { + return Base::newObject(); +} + +ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, const QString& fileName) { +} + +ScriptValuePointer ScriptEngineQtScript::newQObject(QObject* obj) { +} + +ScriptValuePointer ScriptEngineQtScript::newValue(bool value) { +} + +ScriptValuePointer ScriptEngineQtScript::newValue(int value) { +} + +ScriptValuePointer ScriptEngineQtScript::newValue(uint value) { +} + +ScriptValuePointer ScriptEngineQtScript::newValue(double value) { +} + +ScriptValuePointer ScriptEngineQtScript::newValue(const QString& value) { +} + +ScriptValuePointer ScriptEngineQtScript::newValue(const QLatin1String& value) { +} + +ScriptValuePointer ScriptEngineQtScript::newValue(const char* value) { +} + +ScriptValuePointer ScriptEngineQtScript::newVariant(const QVariant& value) { +} + +ScriptValuePointer ScriptEngineQtScript::nullValue() { + return Base::nullValue(); +} + +void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype) { +} + +ScriptValuePointer ScriptEngineQtScript::undefinedValue() { + return Base::undefinedValue(); +} +*/ \ No newline at end of file diff --git a/libraries/script-engine-qtscript/src/ScriptEngineQtScript.h b/libraries/script-engine-qtscript/src/ScriptEngineQtScript.h new file mode 100644 index 00000000000..b1a8b2460f0 --- /dev/null +++ b/libraries/script-engine-qtscript/src/ScriptEngineQtScript.h @@ -0,0 +1,397 @@ +// +// ScriptEngineQtScript.h +// libraries/script-engine-qtscript/src +// +// Created by Brad Hefta-Gaub on 12/14/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptEngineQtScript_h +#define hifi_ScriptEngineQtScript_h + +//#include +//#include + +//#include +//#include +//#include +//#include +//#include + +#include +#include +#include +#include +#include +#include +#include + +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +#include + +//#include "PointerEvent.h" +#include "ArrayBufferClass.h" +//#include "AssetScriptingInterface.h" +//#include "AudioScriptingInterface.h" +#include "BaseScriptEngine.h" +//#include "ExternalResource.h" +//#include "Quat.h" +//#include "Mat4.h" +//#include "ScriptCache.h" +//#include "ScriptUUID.h" +//#include "Vec3.h" +//#include "ConsoleScriptingInterface.h" +//#include "SettingHandle.h" +//#include "Profile.h" + +//class QScriptEngineDebugger; +class ScriptManager; + +Q_DECLARE_METATYPE(ScriptEngineQtScriptPointer) + +/**jsdoc + * The Script API provides facilities for working with scripts. + * + * @namespace Script + * + * @hifi-interface + * @hifi-client-entity + * @hifi-avatar + * @hifi-server-entity + * @hifi-assignment-client + * + * @property {string} context - The context that the script is running in: + *
    + *
  • "client": An Interface or avatar script.
  • + *
  • "entity_client": A client entity script.
  • + *
  • "entity_server": A server entity script.
  • + *
  • "agent": An assignment client script.
  • + *
+ * Read-only. + * @property {string} type - The type of script that is running: + *
    + *
  • "client": An Interface script.
  • + *
  • "entity_client": A client entity script.
  • + *
  • "avatar": An avatar script.
  • + *
  • "entity_server": A server entity script.
  • + *
  • "agent": An assignment client script.
  • + *
+ * Read-only. + * @property {string} filename - The filename of the script file. + * Read-only. + * @property {Script.ResourceBuckets} ExternalPaths - External resource buckets. + */ +class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { + Q_OBJECT + using Base = BaseScriptEngine; + +public: // ScriptEngine implementation + virtual ScriptValuePointer globalObject() const; + virtual ScriptManager* manager() const; + virtual ScriptValuePointer newArray(uint length = 0); + virtual ScriptValuePointer newArrayBuffer(const QByteArray& message); + virtual ScriptValuePointer newObject(); + virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName); + virtual ScriptValuePointer newQObject(QObject* obj); + virtual ScriptValuePointer newValue(bool value); + virtual ScriptValuePointer newValue(int value); + virtual ScriptValuePointer newValue(uint value); + virtual ScriptValuePointer newValue(double value); + virtual ScriptValuePointer newValue(const QString& value); + virtual ScriptValuePointer newValue(const QLatin1String& value); + virtual ScriptValuePointer newValue(const char* value); + virtual ScriptValuePointer newVariant(const QVariant& value); + virtual ScriptValuePointer nullValue(); + virtual void setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype); + virtual ScriptValuePointer undefinedValue(); + +public: + ScriptEngineQtScript(ScriptManager* scriptManager = nullptr); + ~ScriptEngineQtScript(); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can + // properly ensure they are only called on the correct thread + + /**jsdoc + * @function Script.registerGlobalObject + * @param {string} name - Name. + * @param {object} object - Object. + * @deprecated This function is deprecated and will be removed. + */ + /// registers a global object by name + Q_INVOKABLE void registerGlobalObject(const QString& name, QObject* object); + + /**jsdoc + * @function Script.registerGetterSetter + * @param {string} name - Name. + * @param {function} getter - Getter. + * @param {function} setter - Setter. + * @param {string} [parent=""] - Parent. + * @deprecated This function is deprecated and will be removed. + */ + /// registers a global getter/setter + Q_INVOKABLE void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, + QScriptEngine::FunctionSignature setter, const QString& parent = QString("")); + + /**jsdoc + * @function Script.registerFunction + * @param {string} name - Name. + * @param {function} function - Function. + * @param {number} [numArguments=-1] - Number of arguments. + * @deprecated This function is deprecated and will be removed. + */ + /// register a global function + Q_INVOKABLE void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); + + /**jsdoc + * @function Script.registerFunction + * @param {string} parent - Parent. + * @param {string} name - Name. + * @param {function} function - Function. + * @param {number} [numArguments=-1] - Number of arguments. + * @deprecated This function is deprecated and will be removed. + */ + /// register a function as a method on a previously registered global object + Q_INVOKABLE void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature fun, + int numArguments = -1); + + /**jsdoc + * @function Script.registerEnum + * @param {string} name - Name. + * @param {object} enum - Enum. + * @deprecated This function is deprecated and will be removed. + */ + // WARNING: This function must be called after a registerGlobalObject that creates the namespace this enum is located in, or + // the globalObject won't function. E.g., if you have a Foo object and a Foo.FooType enum, Foo must be registered first. + /// registers a global enum + Q_INVOKABLE void registerEnum(const QString& enumName, QMetaEnum newEnum); + + /**jsdoc + * @function Script.registerValue + * @param {string} name - Name. + * @param {object} value - Value. + * @deprecated This function is deprecated and will be removed. + */ + /// registers a global object by name + Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value); + + /**jsdoc + * @function Script.evaluate + * @param {string} program - Program. + * @param {string} filename - File name. + * @param {number} [lineNumber=-1] - Line number. + * @returns {object} Object. + * @deprecated This function is deprecated and will be removed. + */ + /// evaluate some code in the context of the ScriptEngineQtScript and return the result + Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName, int lineNumber = 1); // this is also used by the script tool widget + + /**jsdoc + * @function Script.evaluateInClosure + * @param {object} locals - Locals. + * @param {object} program - Program. + * @returns {object} Object. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE QScriptValue evaluateInClosure(const QScriptValue& locals, const QScriptProgram& program); + + /**jsdoc + * Checks whether the application was compiled as a debug build. + * @function Script.isDebugMode + * @returns {boolean} true if the application was compiled as a debug build, false if it was + * compiled as a release build. + */ + Q_INVOKABLE bool isDebugMode() const; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MODULE related methods + + /**jsdoc + * Prints a message to the program log and emits {@link Script.printedMessage}. + *

Alternatively, you can use {@link print} or one of the {@link console} API methods.

+ * @function Script.print + * @param {string} message - The message to print. + */ + Q_INVOKABLE void print(const QString& message); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Entity Script Related methods + + /**jsdoc + * Manually runs the JavaScript garbage collector which reclaims memory by disposing of objects that are no longer + * reachable. + * @function Script.requestGarbageCollection + */ + Q_INVOKABLE void requestGarbageCollection() { collectGarbage(); } + + bool isRunning() const { return _isRunning; } // used by ScriptWidget + + bool isDebuggable() const { return _debuggable; } + + void disconnectNonEssentialSignals(); + + // NOTE - this is used by the TypedArray implementation. we need to review this for thread safety + ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } + +public slots: + + /**jsdoc + * @function Script.updateMemoryCost + * @param {number} deltaSize - Delta size. + * @deprecated This function is deprecated and will be removed. + */ + void updateMemoryCost(const qint64&); + +signals: + + /**jsdoc + * Triggered frequently at a system-determined interval. + * @function Script.update + * @param {number} deltaTime - The time since the last update, in s. + * @returns {Signal} + * @example Report script update intervals. + * Script.update.connect(function (deltaTime) { + * print("Update: " + deltaTime); + * }); + */ + void update(float deltaTime); + + /**jsdoc + * @function Script.finished + * @param {string} filename - File name. + * @param {object} engine - Engine. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void finished(const QString& fileNameString, ScriptEngineQtScriptPointer); + + /**jsdoc + * @function Script.cleanupMenuItem + * @param {string} menuItem - Menu item. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void cleanupMenuItem(const QString& menuItemString); + + /**jsdoc + * Triggered when the script prints a message to the program log via {@link print}, {@link Script.print}, + * {@link console.log}, {@link console.debug}, {@link console.group}, {@link console.groupEnd}, {@link console.time}, or + * {@link console.timeEnd}. + * @function Script.printedMessage + * @param {string} message - The message. + * @param {string} scriptName - The name of the script that generated the message. + * @returns {Signal} + */ + void printedMessage(const QString& message, const QString& scriptName); + + /**jsdoc + * Triggered when the script generates an error, {@link console.error} or {@link console.exception} is called, or + * {@link console.assert} is called and fails. + * @function Script.errorMessage + * @param {string} message - The error message. + * @param {string} scriptName - The name of the script that generated the error message. + * @returns {Signal} + */ + void errorMessage(const QString& message, const QString& scriptName); + + /**jsdoc + * Triggered when the script generates a warning or {@link console.warn} is called. + * @function Script.warningMessage + * @param {string} message - The warning message. + * @param {string} scriptName - The name of the script that generated the warning message. + * @returns {Signal} + */ + void warningMessage(const QString& message, const QString& scriptName); + + /**jsdoc + * Triggered when the script generates an information message or {@link console.info} is called. + * @function Script.infoMessage + * @param {string} message - The information message. + * @param {string} scriptName - The name of the script that generated the information message. + * @returns {Signal} + */ + void infoMessage(const QString& message, const QString& scriptName); + + /**jsdoc + * Triggered when the running state of the script changes, e.g., from running to stopping. + * @function Script.runningStateChanged + * @returns {Signal} + */ + void runningStateChanged(); + + /**jsdoc + * @function Script.clearDebugWindow + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void clearDebugWindow(); + + /**jsdoc + * @function Script.loadScript + * @param {string} scriptName - Script name. + * @param {boolean} isUserLoaded - Is user loaded. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void loadScript(const QString& scriptName, bool isUserLoaded); + + /**jsdoc + * @function Script.reloadScript + * @param {string} scriptName - Script name. + * @param {boolean} isUserLoaded - Is user loaded. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void reloadScript(const QString& scriptName, bool isUserLoaded); + + /**jsdoc + * Triggered when the script has stopped. + * @function Script.doneRunning + * @returns {Signal} + */ + void doneRunning(); + + /**jsdoc + * @function Script.entityScriptDetailsUpdated + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + // Emitted when an entity script is added or removed, or when the status of an entity + // script is updated (goes from RUNNING to ERROR_RUNNING_SCRIPT, for example) + void entityScriptDetailsUpdated(); + +protected: + + /**jsdoc + * @function Script.executeOnScriptThread + * @param {function} function - Function. + * @param {ConnectionType} [type=2] - Connection type. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void executeOnScriptThread(std::function function, const Qt::ConnectionType& type = Qt::QueuedConnection ); + + QPointer _manager; + + std::atomic _isRunning { false }; + + bool _isThreaded { false }; + QScriptEngineDebugger* _debugger { nullptr }; + bool _debuggable { false }; + qint64 _lastUpdate; + + ArrayBufferClass* _arrayBufferClass; +}; + +#endif // hifi_ScriptEngineQtScript_h diff --git a/libraries/script-engine/src/TypedArrayPrototype.cpp b/libraries/script-engine-qtscript/src/TypedArrayPrototype.cpp similarity index 99% rename from libraries/script-engine/src/TypedArrayPrototype.cpp rename to libraries/script-engine-qtscript/src/TypedArrayPrototype.cpp index a1f3ff87e8d..17da12b845c 100644 --- a/libraries/script-engine/src/TypedArrayPrototype.cpp +++ b/libraries/script-engine-qtscript/src/TypedArrayPrototype.cpp @@ -11,6 +11,8 @@ #include "TypedArrayPrototype.h" +#include + #include "TypedArrays.h" Q_DECLARE_METATYPE(QByteArray*) diff --git a/libraries/script-engine/src/TypedArrayPrototype.h b/libraries/script-engine-qtscript/src/TypedArrayPrototype.h similarity index 89% rename from libraries/script-engine/src/TypedArrayPrototype.h rename to libraries/script-engine-qtscript/src/TypedArrayPrototype.h index 86d578ace0b..3539016ff5b 100644 --- a/libraries/script-engine/src/TypedArrayPrototype.h +++ b/libraries/script-engine-qtscript/src/TypedArrayPrototype.h @@ -12,7 +12,9 @@ #ifndef hifi_TypedArrayPrototype_h #define hifi_TypedArrayPrototype_h -#include "ArrayBufferViewClass.h" +#include +#include +#include class TypedArrayPrototype : public QObject, public QScriptable { Q_OBJECT diff --git a/libraries/script-engine/src/TypedArrays.cpp b/libraries/script-engine-qtscript/src/TypedArrays.cpp similarity index 92% rename from libraries/script-engine/src/TypedArrays.cpp rename to libraries/script-engine-qtscript/src/TypedArrays.cpp index f2c3d3fd3db..8143dfb1fa7 100644 --- a/libraries/script-engine/src/TypedArrays.cpp +++ b/libraries/script-engine-qtscript/src/TypedArrays.cpp @@ -13,12 +13,17 @@ #include -#include "ScriptEngine.h" +#include + +#include + +#include "ArrayBufferClass.h" +#include "ScriptEngineQtScript.h" #include "TypedArrayPrototype.h" Q_DECLARE_METATYPE(QByteArray*) -TypedArray::TypedArray(ScriptEngine* scriptEngine, QString name) : ArrayBufferViewClass(scriptEngine) { +TypedArray::TypedArray(ScriptEngineQtScript* scriptEngine, QString name) : ArrayBufferViewClass(scriptEngine) { _bytesPerElementName = engine()->toStringHandle(BYTES_PER_ELEMENT_PROPERTY_NAME.toLatin1()); _lengthName = engine()->toStringHandle(LENGTH_PROPERTY_NAME.toLatin1()); _name = engine()->toStringHandle(name.toLatin1()); @@ -229,7 +234,7 @@ void setPropertyHelper(QByteArray* arrayBuffer, const QScriptString& name, uint } } -Int8ArrayClass::Int8ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, INT_8_ARRAY_CLASS_NAME) { +Int8ArrayClass::Int8ArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, INT_8_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(qint8)); } @@ -245,7 +250,7 @@ void Int8ArrayClass::setProperty(QScriptValue &object, const QScriptString &name setPropertyHelper(ba, name, id, value); } -Uint8ArrayClass::Uint8ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, UINT_8_ARRAY_CLASS_NAME) { +Uint8ArrayClass::Uint8ArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, UINT_8_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(quint8)); } @@ -261,7 +266,7 @@ void Uint8ArrayClass::setProperty(QScriptValue& object, const QScriptString& nam setPropertyHelper(ba, name, id, value); } -Uint8ClampedArrayClass::Uint8ClampedArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, UINT_8_CLAMPED_ARRAY_CLASS_NAME) { +Uint8ClampedArrayClass::Uint8ClampedArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, UINT_8_CLAMPED_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(quint8)); } @@ -287,7 +292,7 @@ void Uint8ClampedArrayClass::setProperty(QScriptValue& object, const QScriptStri } } -Int16ArrayClass::Int16ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, INT_16_ARRAY_CLASS_NAME) { +Int16ArrayClass::Int16ArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, INT_16_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(qint16)); } @@ -303,7 +308,7 @@ void Int16ArrayClass::setProperty(QScriptValue& object, const QScriptString& nam setPropertyHelper(ba, name, id, value); } -Uint16ArrayClass::Uint16ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, UINT_16_ARRAY_CLASS_NAME) { +Uint16ArrayClass::Uint16ArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, UINT_16_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(quint16)); } @@ -319,7 +324,7 @@ void Uint16ArrayClass::setProperty(QScriptValue& object, const QScriptString& na setPropertyHelper(ba, name, id, value); } -Int32ArrayClass::Int32ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, INT_32_ARRAY_CLASS_NAME) { +Int32ArrayClass::Int32ArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, INT_32_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(qint32)); } @@ -335,7 +340,7 @@ void Int32ArrayClass::setProperty(QScriptValue& object, const QScriptString& nam setPropertyHelper(ba, name, id, value); } -Uint32ArrayClass::Uint32ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, UINT_32_ARRAY_CLASS_NAME) { +Uint32ArrayClass::Uint32ArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, UINT_32_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(quint32)); } @@ -352,7 +357,7 @@ void Uint32ArrayClass::setProperty(QScriptValue& object, const QScriptString& na setPropertyHelper(ba, name, id, value); } -Float32ArrayClass::Float32ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, FLOAT_32_ARRAY_CLASS_NAME) { +Float32ArrayClass::Float32ArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, FLOAT_32_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(float)); } @@ -389,7 +394,7 @@ void Float32ArrayClass::setProperty(QScriptValue& object, const QScriptString& n } } -Float64ArrayClass::Float64ArrayClass(ScriptEngine* scriptEngine) : TypedArray(scriptEngine, FLOAT_64_ARRAY_CLASS_NAME) { +Float64ArrayClass::Float64ArrayClass(ScriptEngineQtScript* scriptEngine) : TypedArray(scriptEngine, FLOAT_64_ARRAY_CLASS_NAME) { setBytesPerElement(sizeof(double)); } diff --git a/libraries/script-engine/src/TypedArrays.h b/libraries/script-engine-qtscript/src/TypedArrays.h similarity index 89% rename from libraries/script-engine/src/TypedArrays.h rename to libraries/script-engine-qtscript/src/TypedArrays.h index 141e7870d90..24a3bda04f6 100644 --- a/libraries/script-engine/src/TypedArrays.h +++ b/libraries/script-engine-qtscript/src/TypedArrays.h @@ -30,7 +30,7 @@ static const QString FLOAT_64_ARRAY_CLASS_NAME = "Float64Array"; class TypedArray : public ArrayBufferViewClass { Q_OBJECT public: - TypedArray(ScriptEngine* scriptEngine, QString name); + TypedArray(ScriptEngineQtScript* scriptEngine, QString name); virtual QScriptValue newInstance(quint32 length); virtual QScriptValue newInstance(QScriptValue array); virtual QScriptValue newInstance(QScriptValue buffer, quint32 byteOffset, quint32 length); @@ -67,7 +67,7 @@ class TypedArray : public ArrayBufferViewClass { class Int8ArrayClass : public TypedArray { Q_OBJECT public: - Int8ArrayClass(ScriptEngine* scriptEngine); + Int8ArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; @@ -76,7 +76,7 @@ class Int8ArrayClass : public TypedArray { class Uint8ArrayClass : public TypedArray { Q_OBJECT public: - Uint8ArrayClass(ScriptEngine* scriptEngine); + Uint8ArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; @@ -85,7 +85,7 @@ class Uint8ArrayClass : public TypedArray { class Uint8ClampedArrayClass : public TypedArray { Q_OBJECT public: - Uint8ClampedArrayClass(ScriptEngine* scriptEngine); + Uint8ClampedArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; @@ -94,7 +94,7 @@ class Uint8ClampedArrayClass : public TypedArray { class Int16ArrayClass : public TypedArray { Q_OBJECT public: - Int16ArrayClass(ScriptEngine* scriptEngine); + Int16ArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; @@ -103,7 +103,7 @@ class Int16ArrayClass : public TypedArray { class Uint16ArrayClass : public TypedArray { Q_OBJECT public: - Uint16ArrayClass(ScriptEngine* scriptEngine); + Uint16ArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; @@ -112,7 +112,7 @@ class Uint16ArrayClass : public TypedArray { class Int32ArrayClass : public TypedArray { Q_OBJECT public: - Int32ArrayClass(ScriptEngine* scriptEngine); + Int32ArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; @@ -121,7 +121,7 @@ class Int32ArrayClass : public TypedArray { class Uint32ArrayClass : public TypedArray { Q_OBJECT public: - Uint32ArrayClass(ScriptEngine* scriptEngine); + Uint32ArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; @@ -130,7 +130,7 @@ class Uint32ArrayClass : public TypedArray { class Float32ArrayClass : public TypedArray { Q_OBJECT public: - Float32ArrayClass(ScriptEngine* scriptEngine); + Float32ArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; @@ -139,7 +139,7 @@ class Float32ArrayClass : public TypedArray { class Float64ArrayClass : public TypedArray { Q_OBJECT public: - Float64ArrayClass(ScriptEngine* scriptEngine); + Float64ArrayClass(ScriptEngineQtScript* scriptEngine); QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 6def6c185fa..f26ce434822 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,18 +1,28 @@ set(TARGET_NAME script-engine) # FIXME Move undo scripting interface to application and remove Widgets -setup_hifi_library(Gui Network Script ScriptTools WebSockets Widgets) +setup_hifi_library(Network WebSockets) target_zlib() if (NOT ANDROID) target_quazip() endif () -link_hifi_libraries(shared networking shaders material-networking model-networking recording avatars model-serializers entities controllers animation audio midi) -include_hifi_library_headers(gl) -include_hifi_library_headers(hfm) +link_hifi_libraries(script-engine-qtscript shaders) +include_hifi_library_headers(animation) +include_hifi_library_headers(audio) +include_hifi_library_headers(avatars) +include_hifi_library_headers(controllers) +include_hifi_library_headers(entities) include_hifi_library_headers(gpu) -include_hifi_library_headers(ktx) +include_hifi_library_headers(hfm) include_hifi_library_headers(image) +include_hifi_library_headers(ktx) include_hifi_library_headers(graphics) +include_hifi_library_headers(material-networking) +include_hifi_library_headers(model-networking) +include_hifi_library_headers(model-serializers) +include_hifi_library_headers(networking) include_hifi_library_headers(octree) -include_hifi_library_headers(procedural) \ No newline at end of file +include_hifi_library_headers(procedural) +include_hifi_library_headers(recording) +include_hifi_library_headers(shared) diff --git a/libraries/script-engine/src/AbstractScriptingServicesInterface.h b/libraries/script-engine/src/AbstractScriptingServicesInterface.h index ac26b166b6c..24d821fa529 100644 --- a/libraries/script-engine/src/AbstractScriptingServicesInterface.h +++ b/libraries/script-engine/src/AbstractScriptingServicesInterface.h @@ -12,13 +12,16 @@ #ifndef hifi_AbstractScriptingServicesInterface_h #define hifi_AbstractScriptingServicesInterface_h -#include +#include + +class ScriptManager; +using ScriptManagerPointer = QSharedPointer; /// Interface provided by Application to other objects that need access to scripting services of the application class AbstractScriptingServicesInterface { public: /// Registers application specific services with a script engine. - virtual void registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) = 0; + virtual void registerScriptEngineWithApplicationServices(const ScriptManagerPointer& scriptEngine) = 0; }; diff --git a/libraries/script-engine/src/ArrayBufferClass.cpp b/libraries/script-engine/src/ArrayBufferClass.cpp deleted file mode 100644 index 6734114932f..00000000000 --- a/libraries/script-engine/src/ArrayBufferClass.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// -// ArrayBufferClass.cpp -// -// -// Created by Clement on 7/3/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "ArrayBufferClass.h" - -#include - -#include "ArrayBufferPrototype.h" -#include "DataViewClass.h" -#include "ScriptEngine.h" -#include "TypedArrays.h" - - -static const QString CLASS_NAME = "ArrayBuffer"; - -// FIXME: Q_DECLARE_METATYPE is global and really belongs in a shared header file, not per .cpp like this -// (see DataViewClass.cpp, etc. which would also have to be updated to resolve) -Q_DECLARE_METATYPE(QScriptClass*) -Q_DECLARE_METATYPE(QByteArray*) -int qScriptClassPointerMetaTypeId = qRegisterMetaType(); -int qByteArrayPointerMetaTypeId = qRegisterMetaType(); - -ArrayBufferClass::ArrayBufferClass(ScriptEngine* scriptEngine) : -QObject(scriptEngine), -QScriptClass(scriptEngine) { - qScriptRegisterMetaType(engine(), toScriptValue, fromScriptValue); - QScriptValue global = engine()->globalObject(); - - // Save string handles for quick lookup - _name = engine()->toStringHandle(CLASS_NAME.toLatin1()); - _byteLength = engine()->toStringHandle(BYTE_LENGTH_PROPERTY_NAME.toLatin1()); - - // build prototype - _proto = engine()->newQObject(new ArrayBufferPrototype(this), - QScriptEngine::QtOwnership, - QScriptEngine::SkipMethodsInEnumeration | - QScriptEngine::ExcludeSuperClassMethods | - QScriptEngine::ExcludeSuperClassProperties); - _proto.setPrototype(global.property("Object").property("prototype")); - - // Register constructor - _ctor = engine()->newFunction(construct, _proto); - _ctor.setData(engine()->toScriptValue(this)); - - engine()->globalObject().setProperty(name(), _ctor); - - // Registering other array types - // The script engine is there parent so it'll delete them with itself - new DataViewClass(scriptEngine); - new Int8ArrayClass(scriptEngine); - new Uint8ArrayClass(scriptEngine); - new Uint8ClampedArrayClass(scriptEngine); - new Int16ArrayClass(scriptEngine); - new Uint16ArrayClass(scriptEngine); - new Int32ArrayClass(scriptEngine); - new Uint32ArrayClass(scriptEngine); - new Float32ArrayClass(scriptEngine); - new Float64ArrayClass(scriptEngine); -} - -QScriptValue ArrayBufferClass::newInstance(qint32 size) { - const qint32 MAX_LENGTH = 100000000; - if (size < 0) { - engine()->evaluate("throw \"ArgumentError: negative length\""); - return QScriptValue(); - } - if (size > MAX_LENGTH) { - engine()->evaluate("throw \"ArgumentError: absurd length\""); - return QScriptValue(); - } - // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. -#if defined(Q_OS_WIN) || defined(Q_OS_MAC) - engine()->reportAdditionalMemoryCost(size); -#endif - QScriptEngine* eng = engine(); - QVariant variant = QVariant::fromValue(QByteArray(size, 0)); - QScriptValue data = eng->newVariant(variant); - return engine()->newObject(this, data); -} - -QScriptValue ArrayBufferClass::newInstance(const QByteArray& ba) { - QScriptValue data = engine()->newVariant(QVariant::fromValue(ba)); - return engine()->newObject(this, data); -} - -QScriptValue ArrayBufferClass::construct(QScriptContext* context, QScriptEngine* engine) { - ArrayBufferClass* cls = qscriptvalue_cast(context->callee().data()); - if (!cls) { - // return if callee (function called) is not of type ArrayBuffer - return QScriptValue(); - } - QScriptValue arg = context->argument(0); - if (!arg.isValid() || !arg.isNumber()) { - return QScriptValue(); - } - - quint32 size = arg.toInt32(); - QScriptValue newObject = cls->newInstance(size); - - if (context->isCalledAsConstructor()) { - // if called with keyword new, replace this object. - context->setThisObject(newObject); - return engine->undefinedValue(); - } - - return newObject; -} - -QScriptClass::QueryFlags ArrayBufferClass::queryProperty(const QScriptValue& object, - const QScriptString& name, - QueryFlags flags, uint* id) { - QByteArray* ba = qscriptvalue_cast(object.data()); - if (ba && name == _byteLength) { - // if the property queried is byteLength, only handle read access - return flags &= HandlesReadAccess; - } - return 0; // No access -} - -QScriptValue ArrayBufferClass::property(const QScriptValue& object, - const QScriptString& name, uint id) { - QByteArray* ba = qscriptvalue_cast(object.data()); - if (ba && name == _byteLength) { - return ba->length(); - } - return QScriptValue(); -} - -QScriptValue::PropertyFlags ArrayBufferClass::propertyFlags(const QScriptValue& object, - const QScriptString& name, uint id) { - return QScriptValue::Undeletable; -} - -QString ArrayBufferClass::name() const { - return _name.toString(); -} - -QScriptValue ArrayBufferClass::prototype() const { - return _proto; -} - -QScriptValue ArrayBufferClass::toScriptValue(QScriptEngine* engine, const QByteArray& ba) { - QScriptValue ctor = engine->globalObject().property(CLASS_NAME); - ArrayBufferClass* cls = qscriptvalue_cast(ctor.data()); - if (!cls) { - if (engine->currentContext()) { - engine->currentContext()->throwError("arrayBufferClass::toScriptValue -- could not get " + CLASS_NAME + " class constructor"); - } - return QScriptValue::NullValue; - } - return cls->newInstance(ba); -} - -void ArrayBufferClass::fromScriptValue(const QScriptValue& object, QByteArray& byteArray) { - if (object.isString()) { - // UTF-8 encoded String - byteArray = object.toString().toUtf8(); - } else if (object.isArray()) { - // Array of uint8s eg: [ 128, 3, 25, 234 ] - auto Uint8Array = object.engine()->globalObject().property("Uint8Array"); - auto typedArray = Uint8Array.construct(QScriptValueList{object}); - if (QByteArray* buffer = qscriptvalue_cast(typedArray.property("buffer"))) { - byteArray = *buffer; - } - } else if (object.isObject()) { - // ArrayBuffer instance (or any JS class that supports coercion into QByteArray*) - if (QByteArray* buffer = qscriptvalue_cast(object.data())) { - byteArray = *buffer; - } - } -} - diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index f088ad7a38c..b301c0136c2 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -13,18 +13,20 @@ #include #include -#include #include #include #include -#include #include #include #include #include "ScriptEngine.h" +#include "ScriptEngineCast.h" #include "ScriptEngineLogging.h" +#include "ScriptManager.h" +#include "ScriptValue.h" +#include "ScriptValueUtils.h" #include #include @@ -35,7 +37,9 @@ using Promise = MiniPromise::Promise; AssetScriptingInterface::AssetScriptingInterface(QObject* parent) : BaseAssetScriptingInterface(parent) { qCDebug(scriptengine) << "AssetScriptingInterface::AssetScriptingInterface" << parent; - MiniPromise::registerMetaTypes(parent); + + auto scriptManager = qobject_cast(parent); + scriptRegisterMetaType(scriptManager->engine().get(), promiseToScriptValue, promiseFromScriptValue); } #define JS_VERIFY(cond, error) { if (!this->jsVerify(cond, error)) { return; } } @@ -59,16 +63,17 @@ bool AssetScriptingInterface::initializeCache() { } } -void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { +void AssetScriptingInterface::uploadData(QString data, ScriptValuePointer callback) { auto handler = jsBindCallback(thisObject(), callback); QByteArray dataByteArray = data.toUtf8(); auto upload = DependencyManager::get()->createUpload(dataByteArray); Promise deferred = makePromise(__FUNCTION__); + auto scriptEngine = engine(); deferred->ready([=](QString error, QVariantMap result) { auto url = result.value("url").toString(); auto hash = result.value("hash").toString(); - jsCallback(handler, url, hash); + jsCallback(handler, scriptEngine->newValue(url), scriptEngine->newValue(hash)); }); connect(upload, &AssetUpload::finished, upload, [deferred](AssetUpload* upload, const QString& hash) { @@ -83,12 +88,13 @@ void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) { upload->start(); } -void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) { +void AssetScriptingInterface::setMapping(QString path, QString hash, ScriptValuePointer callback) { auto handler = jsBindCallback(thisObject(), callback); auto setMappingRequest = assetClient()->createSetMappingRequest(path, hash); Promise deferred = makePromise(__FUNCTION__); + auto scriptEngine = engine(); deferred->ready([=](QString error, QVariantMap result) { - jsCallback(handler, error, result); + jsCallback(handler, scriptEngine->newValue(error), result); }); connect(setMappingRequest, &SetMappingRequest::finished, setMappingRequest, [deferred](SetMappingRequest* request) { @@ -107,7 +113,7 @@ void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValu * @typedef {object} Assets.DownloadDataError * @property {string} errorMessage - "" if the download was successful, otherwise a description of the error. */ -void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { +void AssetScriptingInterface::downloadData(QString urlString, ScriptValuePointer callback) { // FIXME: historically this API method failed silently when given a non-atp prefixed // urlString (or if the AssetRequest failed). // .. is that by design or could we update without breaking things to provide better feedback to scripts? @@ -123,9 +129,10 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb auto assetRequest = assetClient->createRequest(hash); Promise deferred = makePromise(__FUNCTION__); + auto scriptEngine = engine(); deferred->ready([=](QString error, QVariantMap result) { // FIXME: to remain backwards-compatible the signature here is "callback(data, n/a)" - jsCallback(handler, result.value("data").toString(), { { "errorMessage", error } }); + jsCallback(handler, scriptEngine->newValue(result.value("data").toString()), { { "errorMessage", error } }); }); connect(assetRequest, &AssetRequest::finished, assetRequest, [deferred](AssetRequest* request) { @@ -149,7 +156,7 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb assetRequest->start(); } -void AssetScriptingInterface::setBakingEnabled(QString path, bool enabled, QScriptValue callback) { +void AssetScriptingInterface::setBakingEnabled(QString path, bool enabled, ScriptValuePointer callback) { auto setBakingEnabledRequest = DependencyManager::get()->createSetBakingEnabledRequest({ path }, enabled); Promise deferred = jsPromiseReady(makePromise(__FUNCTION__), thisObject(), callback); @@ -179,14 +186,15 @@ void AssetScriptingInterface::sendFakedHandshake() { #endif -void AssetScriptingInterface::getMapping(QString asset, QScriptValue callback) { +void AssetScriptingInterface::getMapping(QString asset, ScriptValuePointer callback) { auto path = AssetUtils::getATPUrl(asset).path(); auto handler = jsBindCallback(thisObject(), callback); JS_VERIFY(AssetUtils::isValidFilePath(path), "invalid ATP file path: " + asset + "(path:"+path+")"); - JS_VERIFY(callback.isFunction(), "expected second parameter to be a callback function"); + JS_VERIFY(callback->isFunction(), "expected second parameter to be a callback function"); Promise promise = getAssetInfo(path); + auto scriptEngine = engine(); promise->ready([=](QString error, QVariantMap result) { - jsCallback(handler, error, result.value("hash").toString()); + jsCallback(handler, scriptEngine->newValue(error), scriptEngine->newValue(result.value("hash").toString())); }); } @@ -202,45 +210,46 @@ bool AssetScriptingInterface::jsVerify(bool condition, const QString& error) { return false; } -QScriptValue AssetScriptingInterface::jsBindCallback(QScriptValue scope, QScriptValue callback) { - QScriptValue handler = ::makeScopedHandlerObject(scope, callback); - QScriptValue value = handler.property("callback"); - if (!jsVerify(handler.isObject() && value.isFunction(), - QString("jsBindCallback -- .callback is not a function (%1)").arg(value.toVariant().typeName()))) { - return QScriptValue(); +ScriptValuePointer AssetScriptingInterface::jsBindCallback(ScriptValuePointer scope, ScriptValuePointer callback) { + ScriptValuePointer handler = ::makeScopedHandlerObject(scope, callback); + ScriptValuePointer value = handler->property("callback"); + if (!jsVerify(handler->isObject() && value->isFunction(), + QString("jsBindCallback -- .callback is not a function (%1)").arg(value->toVariant().typeName()))) { + return ScriptValuePointer(); } return handler; } -Promise AssetScriptingInterface::jsPromiseReady(Promise promise, QScriptValue scope, QScriptValue callback) { +Promise AssetScriptingInterface::jsPromiseReady(Promise promise, ScriptValuePointer scope, ScriptValuePointer callback) { auto handler = jsBindCallback(scope, callback); - if (!jsVerify(handler.isValid(), "jsPromiseReady -- invalid callback handler")) { + if (!jsVerify(handler->isValid(), "jsPromiseReady -- invalid callback handler")) { return nullptr; } - return promise->ready([this, handler](QString error, QVariantMap result) { - jsCallback(handler, error, result); + auto scriptEngine = engine(); + return promise->ready([this, handler, scriptEngine](QString error, QVariantMap result) { + jsCallback(handler, scriptEngine->newValue(error), result); }); } -void AssetScriptingInterface::jsCallback(const QScriptValue& handler, - const QScriptValue& error, const QScriptValue& result) { +void AssetScriptingInterface::jsCallback(const ScriptValuePointer& handler, + const ScriptValuePointer& error, const ScriptValuePointer& result) { Q_ASSERT(thread() == QThread::currentThread()); - auto errorValue = !error.toBool() ? QScriptValue::NullValue : error; - JS_VERIFY(handler.isObject() && handler.property("callback").isFunction(), + auto errorValue = !error->toBool() ? engine()->nullValue() : error; + JS_VERIFY(handler->isObject() && handler->property("callback")->isFunction(), QString("jsCallback -- .callback is not a function (%1)") - .arg(handler.property("callback").toVariant().typeName())); + .arg(handler->property("callback")->toVariant().typeName())); ::callScopedHandlerObject(handler, errorValue, result); } -void AssetScriptingInterface::jsCallback(const QScriptValue& handler, - const QScriptValue& error, const QVariantMap& result) { +void AssetScriptingInterface::jsCallback(const ScriptValuePointer& handler, + const ScriptValuePointer& error, const QVariantMap& result) { Q_ASSERT(thread() == QThread::currentThread()); - Q_ASSERT(handler.engine()); - auto engine = handler.engine(); + Q_ASSERT(handler->engine()); + auto engine = handler->engine(); jsCallback(handler, error, engine->toScriptValue(result)); } -void AssetScriptingInterface::deleteAsset(QScriptValue options, QScriptValue scope, QScriptValue callback) { +void AssetScriptingInterface::deleteAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { jsVerify(false, "TODO: deleteAsset API"); } @@ -270,14 +279,14 @@ void AssetScriptingInterface::deleteAsset(QScriptValue options, QScriptValue sco * @property {boolean} [wasRedirected] - true if the downloaded data is the baked version of the asset, * false if it isn't baked. */ -void AssetScriptingInterface::getAsset(QScriptValue options, QScriptValue scope, QScriptValue callback) { - JS_VERIFY(options.isObject() || options.isString(), "expected request options Object or URL as first parameter"); - - auto decompress = options.property("decompress").toBool() || options.property("compressed").toBool(); - auto responseType = options.property("responseType").toString().toLower(); - auto url = options.property("url").toString(); - if (options.isString()) { - url = options.toString(); +void AssetScriptingInterface::getAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { + JS_VERIFY(options->isObject() || options->isString(), "expected request options Object or URL as first parameter"); + + auto decompress = options->property("decompress")->toBool() || options->property("compressed")->toBool(); + auto responseType = options->property("responseType")->toString().toLower(); + auto url = options->property("url")->toString(); + if (options->isString()) { + url = options->toString(); } if (responseType.isEmpty()) { responseType = "text"; @@ -336,10 +345,10 @@ void AssetScriptingInterface::getAsset(QScriptValue options, QScriptValue scope, * @property {boolean} [wasRedirected] - true if the resolved data is for the baked version of the asset, * false if it isn't. */ -void AssetScriptingInterface::resolveAsset(QScriptValue options, QScriptValue scope, QScriptValue callback) { +void AssetScriptingInterface::resolveAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { const QString& URL{ "url" }; - auto url = (options.isString() ? options : options.property(URL)).toString(); + auto url = (options->isString() ? options : options->property(URL))->toString(); auto asset = AssetUtils::getATPUrl(url).path(); JS_VERIFY(AssetUtils::isValidFilePath(asset) || AssetUtils::isValidHash(asset), @@ -363,10 +372,10 @@ void AssetScriptingInterface::resolveAsset(QScriptValue options, QScriptValue sc * @property {string|object|ArrayBuffer} [response] - The decompressed data. * @property {Assets.ResponseType} [responseType] - The type of the decompressed data in response. */ -void AssetScriptingInterface::decompressData(QScriptValue options, QScriptValue scope, QScriptValue callback) { - auto data = options.property("data"); - QByteArray dataByteArray = qscriptvalue_cast(data); - auto responseType = options.property("responseType").toString().toLower(); +void AssetScriptingInterface::decompressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { + auto data = options->property("data"); + QByteArray dataByteArray = scriptvalue_cast(data); + auto responseType = options->property("responseType")->toString().toLower(); if (responseType.isEmpty()) { responseType = "text"; } @@ -404,10 +413,10 @@ namespace { * @property {string} [contentType] - The MIME type of the compressed data, i.e., "application/gzip". * @property {ArrayBuffer} [data] - The compressed data. */ -void AssetScriptingInterface::compressData(QScriptValue options, QScriptValue scope, QScriptValue callback) { - auto data = options.property("data").isValid() ? options.property("data") : options; - QByteArray dataByteArray = data.isString() ? data.toString().toUtf8() : qscriptvalue_cast(data); - int level = options.property("level").isNumber() ? options.property("level").toInt32() : DEFAULT_GZIP_COMPRESSION_LEVEL; +void AssetScriptingInterface::compressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { + auto data = options->property("data")->isValid() ? options->property("data") : options; + QByteArray dataByteArray = data->isString() ? data->toString().toUtf8() : scriptvalue_cast(data); + int level = options->property("level")->isNumber() ? options->property("level")->toInt32() : DEFAULT_GZIP_COMPRESSION_LEVEL; JS_VERIFY(level >= DEFAULT_GZIP_COMPRESSION_LEVEL || level <= MAX_GZIP_COMPRESSION_LEVEL, QString("invalid .level %1").arg(level)); jsPromiseReady(compressBytes(dataByteArray, level), scope, callback); } @@ -433,18 +442,18 @@ void AssetScriptingInterface::compressData(QScriptValue options, QScriptValue sc * @property {string} [url] - The atp: URL of the content: using the path if specified, otherwise the hash. * @property {string} [path] - The uploaded content's mapped path, if specified. */ -void AssetScriptingInterface::putAsset(QScriptValue options, QScriptValue scope, QScriptValue callback) { - auto compress = options.property("compress").toBool() || options.property("compressed").toBool(); - auto data = options.isObject() ? options.property("data") : options; - auto rawPath = options.property("path").toString(); +void AssetScriptingInterface::putAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { + auto compress = options->property("compress")->toBool() || options->property("compressed")->toBool(); + auto data = options->isObject() ? options->property("data") : options; + auto rawPath = options->property("path")->toString(); auto path = AssetUtils::getATPUrl(rawPath).path(); - QByteArray dataByteArray = data.isString() ? data.toString().toUtf8() : qscriptvalue_cast(data); + QByteArray dataByteArray = data->isString() ? data->toString().toUtf8() : scriptvalue_cast(data); JS_VERIFY(path.isEmpty() || AssetUtils::isValidFilePath(path), QString("expected valid ATP file path '%1' ('%2')").arg(rawPath).arg(path)); JS_VERIFY(dataByteArray.size() > 0, - QString("expected non-zero .data (got %1 / #%2 bytes)").arg(data.toVariant().typeName()).arg(dataByteArray.size())); + QString("expected non-zero .data (got %1 / #%2 bytes)").arg(data->toVariant().typeName()).arg(dataByteArray.size())); // [compressed] => uploaded to server => [mapped to path] Promise prepared = makePromise("putAsset::prepared"); @@ -489,8 +498,8 @@ void AssetScriptingInterface::putAsset(QScriptValue options, QScriptValue scope, * @property {string} url - The URL of the cached asset to get information on. Must start with "atp:" or * "cache:". */ -void AssetScriptingInterface::queryCacheMeta(QScriptValue options, QScriptValue scope, QScriptValue callback) { - QString url = options.isString() ? options.toString() : options.property("url").toString(); +void AssetScriptingInterface::queryCacheMeta(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { + QString url = options->isString() ? options->toString() : options->property("url")->toString(); JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url)); jsPromiseReady(Parent::queryCacheMeta(url), scope, callback); } @@ -504,16 +513,16 @@ void AssetScriptingInterface::queryCacheMeta(QScriptValue options, QScriptValue * @property {string} url - The URL of the asset to load from cache. Must start with "atp:" or * "cache:". */ -void AssetScriptingInterface::loadFromCache(QScriptValue options, QScriptValue scope, QScriptValue callback) { +void AssetScriptingInterface::loadFromCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { QString url, responseType; bool decompress = false; - if (options.isString()) { - url = options.toString(); + if (options->isString()) { + url = options->toString(); responseType = "text"; } else { - url = options.property("url").toString(); - responseType = options.property("responseType").isValid() ? options.property("responseType").toString() : "text"; - decompress = options.property("decompress").toBool() || options.property("compressed").toBool(); + url = options->property("url")->toString(); + responseType = options->property("responseType")->isValid() ? options->property("responseType")->toString() : "text"; + decompress = options->property("decompress")->toBool() || options->property("compressed")->toBool(); } JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url)); JS_VERIFY(RESPONSE_TYPES.contains(responseType), @@ -523,14 +532,14 @@ void AssetScriptingInterface::loadFromCache(QScriptValue options, QScriptValue s } bool AssetScriptingInterface::canWriteCacheValue(const QUrl& url) { - auto scriptEngine = qobject_cast(engine()); - if (!scriptEngine) { + auto scriptManager = engine()->manager(); + if (!scriptManager) { return false; } // allow cache writes only from Client, EntityServer and Agent scripts bool isAllowedContext = ( - scriptEngine->isClientScript() || - scriptEngine->isAgentScript() + scriptManager->isClientScript() || + scriptManager->isAgentScript() ); if (!isAllowedContext) { return false; @@ -546,17 +555,17 @@ bool AssetScriptingInterface::canWriteCacheValue(const QUrl& url) { * @property {string} [url] - The URL to associate with the cache item. Must start with "atp:" or * "cache:". If not specified, the URL is "atp:" followed by the SHA256 hash of the content. */ -void AssetScriptingInterface::saveToCache(QScriptValue options, QScriptValue scope, QScriptValue callback) { - JS_VERIFY(options.isObject(), QString("expected options object as first parameter not: %1").arg(options.toVariant().typeName())); +void AssetScriptingInterface::saveToCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { + JS_VERIFY(options->isObject(), QString("expected options object as first parameter not: %1").arg(options->toVariant().typeName())); - QString url = options.property("url").toString(); - QByteArray data = qscriptvalue_cast(options.property("data")); - QVariantMap headers = qscriptvalue_cast(options.property("headers")); + QString url = options->property("url")->toString(); + QByteArray data = scriptvalue_cast(options->property("data")); + QVariantMap headers = scriptvalue_cast(options->property("headers")); saveToCache(url, data, headers, scope, callback); } -void AssetScriptingInterface::saveToCache(const QUrl& rawURL, const QByteArray& data, const QVariantMap& metadata, QScriptValue scope, QScriptValue callback) { +void AssetScriptingInterface::saveToCache(const QUrl& rawURL, const QByteArray& data, const QVariantMap& metadata, ScriptValuePointer scope, ScriptValuePointer callback) { QUrl url = rawURL; if (url.path().isEmpty() && !data.isEmpty()) { // generate a valid ATP URL from the data -- appending any existing fragment or querystring values diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 3ba7632cd0a..8871fdebf6a 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -16,13 +16,16 @@ #include #include -#include -#include #include #include #include -#include #include +#include + +#include "Scriptable.h" + +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The Assets API provides facilities for interacting with the domain's asset server and the client cache. @@ -41,7 +44,7 @@ * @hifi-server-entity * @hifi-assignment-client */ -class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable { +class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { Q_OBJECT public: using Parent = BaseAssetScriptingInterface; @@ -72,7 +75,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * }); * }); */ - Q_INVOKABLE void uploadData(QString data, QScriptValue callback); + Q_INVOKABLE void uploadData(QString data, ScriptValuePointer callback); /**jsdoc * Called when an {@link Assets.downloadData} call is complete. @@ -108,7 +111,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * }); * }, 1000); */ - Q_INVOKABLE void downloadData(QString url, QScriptValue callback); + Q_INVOKABLE void downloadData(QString url, ScriptValuePointer callback); /**jsdoc * Called when an {@link Assets.setMapping} call is complete. @@ -122,7 +125,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * @param {string} hash - The hash in the asset server. * @param {Assets~setMappingCallback} callback - The function to call upon completion. */ - Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); + Q_INVOKABLE void setMapping(QString path, QString hash, ScriptValuePointer callback); /**jsdoc * Called when an {@link Assets.getMapping} call is complete. @@ -146,7 +149,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * }); * } */ - Q_INVOKABLE void getMapping(QString path, QScriptValue callback); + Q_INVOKABLE void getMapping(QString path, ScriptValuePointer callback); /**jsdoc * Called when an {@link Assets.setBakingEnabled} call is complete. @@ -162,7 +165,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * @param {Assets~setBakingEnabledCallback} callback - The function to call upon completion. */ // Note: Second callback parameter not documented because it's always {}. - Q_INVOKABLE void setBakingEnabled(QString path, bool enabled, QScriptValue callback); + Q_INVOKABLE void setBakingEnabled(QString path, bool enabled, ScriptValuePointer callback); #if (PR_BUILD || DEV_BUILD) /** @@ -218,7 +221,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * } * ); */ - Q_INVOKABLE void getAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void getAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Called when an {@link Assets.putAsset} call is complete. @@ -255,7 +258,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * } * ); */ - Q_INVOKABLE void putAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void putAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Called when an {@link Assets.deleteAsset} call is complete. @@ -272,7 +275,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * @param {object} scope - The scope that the callback function is defined in. * @param {Assets~deleteAssetCallback} callback - The function to call upon completion. */ - Q_INVOKABLE void deleteAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void deleteAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Called when an {@link Assets.resolveAsset} call is complete. @@ -306,7 +309,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * } * ); */ - Q_INVOKABLE void resolveAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void resolveAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Called when an {@link Assets.decompressData} call is complete. @@ -327,7 +330,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

*/ - Q_INVOKABLE void decompressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void decompressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Called when an {@link Assets.compressData} call is complete. @@ -349,7 +352,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

*/ - Q_INVOKABLE void compressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void compressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Initializes the cache if it isn't already initialized. @@ -394,7 +397,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * print("- Status: " + JSON.stringify(status)); * }); */ - Q_INVOKABLE void getCacheStatus(QScriptValue scope, QScriptValue callback = QScriptValue()) { + Q_INVOKABLE void getCacheStatus(ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()) { jsPromiseReady(Parent::getCacheStatus(), scope, callback); } @@ -434,7 +437,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * } * ); */ - Q_INVOKABLE void queryCacheMeta(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void queryCacheMeta(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Called when an {@link Assets.loadFromCache} call is complete. @@ -474,7 +477,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * } * ); */ - Q_INVOKABLE void loadFromCache(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void loadFromCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Called when an {@link Assets.saveToCache} call is complete. @@ -513,7 +516,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * } * ); */ - Q_INVOKABLE void saveToCache(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); + Q_INVOKABLE void saveToCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc * Saves asset data to the cache directly, without downloading it from a URL. @@ -533,13 +536,13 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable * scopeOrCallback.

*/ Q_INVOKABLE void saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& metadata, - QScriptValue scope, QScriptValue callback = QScriptValue()); + ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); protected: - QScriptValue jsBindCallback(QScriptValue scope, QScriptValue callback = QScriptValue()); - Promise jsPromiseReady(Promise promise, QScriptValue scope, QScriptValue callback = QScriptValue()); + ScriptValuePointer jsBindCallback(ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Promise jsPromiseReady(Promise promise, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); - void jsCallback(const QScriptValue& handler, const QScriptValue& error, const QVariantMap& result); - void jsCallback(const QScriptValue& handler, const QScriptValue& error, const QScriptValue& result); + void jsCallback(const ScriptValuePointer& handler, const ScriptValuePointer& error, const QVariantMap& result); + void jsCallback(const ScriptValuePointer& handler, const ScriptValuePointer& error, const ScriptValuePointer& result); bool jsVerify(bool condition, const QString& error); }; diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index a55cac292f8..797a5b525d2 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -16,11 +16,13 @@ #include #include "ScriptAudioInjector.h" +#include "ScriptEngine.h" +#include "ScriptEngineCast.h" #include "ScriptEngineLogging.h" -void registerAudioMetaTypes(QScriptEngine* engine) { - qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); - qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue); +void registerAudioMetaTypes(ScriptEngine* engine) { + scriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); + scriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue); } diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 0553679f8a4..05483febc22 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -18,6 +18,7 @@ #include class ScriptAudioInjector; +class ScriptEngine; class AudioScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -287,6 +288,6 @@ class AudioScriptingInterface : public QObject, public Dependency { AbstractAudioInterface* _localAudioInterface { nullptr }; }; -void registerAudioMetaTypes(QScriptEngine* engine); +void registerAudioMetaTypes(ScriptEngine* engine); #endif // hifi_AudioScriptingInterface_h diff --git a/libraries/script-engine/src/ConsoleScriptingInterface.cpp b/libraries/script-engine/src/ConsoleScriptingInterface.cpp index 60de04aa9ea..b36bd547a14 100644 --- a/libraries/script-engine/src/ConsoleScriptingInterface.cpp +++ b/libraries/script-engine/src/ConsoleScriptingInterface.cpp @@ -19,7 +19,10 @@ #include +#include "ScriptContext.h" #include "ScriptEngine.h" +#include "ScriptManager.h" +#include "ScriptValue.h" #define INDENTATION 4 // 1 Tab - 4 spaces const QString LINE_SEPARATOR = "\n "; @@ -27,71 +30,71 @@ const QString SPACE_SEPARATOR = " "; const QString STACK_TRACE_FORMAT = "\n[Stacktrace]%1%2"; QList ConsoleScriptingInterface::_groupDetails = QList(); -QScriptValue ConsoleScriptingInterface::info(QScriptContext* context, QScriptEngine* engine) { - if (ScriptEngine* scriptEngine = qobject_cast(engine)) { - scriptEngine->scriptInfoMessage(appendArguments(context)); +ScriptValuePointer ConsoleScriptingInterface::info(ScriptContext* context, ScriptEngine* engine) { + if (ScriptManager* scriptManager = engine->manager()) { + scriptManager->scriptInfoMessage(appendArguments(context)); } - return QScriptValue::NullValue; + return engine->nullValue(); } -QScriptValue ConsoleScriptingInterface::log(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer ConsoleScriptingInterface::log(ScriptContext* context, ScriptEngine* engine) { QString message = appendArguments(context); if (_groupDetails.count() == 0) { - if (ScriptEngine* scriptEngine = qobject_cast(engine)) { - scriptEngine->scriptPrintedMessage(message); + if (ScriptManager* scriptManager = engine->manager()) { + scriptManager->scriptPrintedMessage(message); } } else { logGroupMessage(message, engine); } - return QScriptValue::NullValue; + return engine->nullValue(); } -QScriptValue ConsoleScriptingInterface::debug(QScriptContext* context, QScriptEngine* engine) { - if (ScriptEngine* scriptEngine = qobject_cast(engine)) { - scriptEngine->scriptPrintedMessage(appendArguments(context)); +ScriptValuePointer ConsoleScriptingInterface::debug(ScriptContext* context, ScriptEngine* engine) { + if (ScriptManager* scriptManager = engine->manager()) { + scriptManager->scriptPrintedMessage(appendArguments(context)); } - return QScriptValue::NullValue; + return engine->nullValue(); } -QScriptValue ConsoleScriptingInterface::warn(QScriptContext* context, QScriptEngine* engine) { - if (ScriptEngine* scriptEngine = qobject_cast(engine)) { - scriptEngine->scriptWarningMessage(appendArguments(context)); +ScriptValuePointer ConsoleScriptingInterface::warn(ScriptContext* context, ScriptEngine* engine) { + if (ScriptManager* scriptManager = engine->manager()) { + scriptManager->scriptWarningMessage(appendArguments(context)); } - return QScriptValue::NullValue; + return engine->nullValue(); } -QScriptValue ConsoleScriptingInterface::error(QScriptContext* context, QScriptEngine* engine) { - if (ScriptEngine* scriptEngine = qobject_cast(engine)) { - scriptEngine->scriptErrorMessage(appendArguments(context)); +ScriptValuePointer ConsoleScriptingInterface::error(ScriptContext* context, ScriptEngine* engine) { + if (ScriptManager* scriptManager = engine->manager()) { + scriptManager->scriptErrorMessage(appendArguments(context)); } - return QScriptValue::NullValue; + return engine->nullValue(); } -QScriptValue ConsoleScriptingInterface::exception(QScriptContext* context, QScriptEngine* engine) { - if (ScriptEngine* scriptEngine = qobject_cast(engine)) { - scriptEngine->scriptErrorMessage(appendArguments(context)); +ScriptValuePointer ConsoleScriptingInterface::exception(ScriptContext* context, ScriptEngine* engine) { + if (ScriptManager* scriptManager = engine->manager()) { + scriptManager->scriptErrorMessage(appendArguments(context)); } - return QScriptValue::NullValue; + return engine->nullValue(); } void ConsoleScriptingInterface::time(QString labelName) { _timerDetails.insert(labelName, QDateTime::currentDateTime().toUTC()); QString message = QString("%1: Timer started").arg(labelName); - if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->scriptPrintedMessage(message); + if (ScriptManager* scriptManager = engine()->manager()) { + scriptManager->scriptPrintedMessage(message); } } void ConsoleScriptingInterface::timeEnd(QString labelName) { - if (ScriptEngine* scriptEngine = qobject_cast(engine())) { + if (ScriptManager* scriptManager = engine()->manager()) { if (!_timerDetails.contains(labelName)) { - scriptEngine->scriptErrorMessage("No such label found " + labelName); + scriptManager->scriptErrorMessage("No such label found " + labelName); return; } if (_timerDetails.value(labelName).isNull()) { _timerDetails.remove(labelName); - scriptEngine->scriptErrorMessage("Invalid start time for " + labelName); + scriptManager->scriptErrorMessage("Invalid start time for " + labelName); return; } QDateTime _startTime = _timerDetails.value(labelName); @@ -101,18 +104,18 @@ void ConsoleScriptingInterface::timeEnd(QString labelName) { QString message = QString("%1: %2ms").arg(labelName).arg(QString::number(diffInMS)); _timerDetails.remove(labelName); - scriptEngine->scriptPrintedMessage(message); + scriptManager->scriptPrintedMessage(message); } } -QScriptValue ConsoleScriptingInterface::assertion(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer ConsoleScriptingInterface::assertion(ScriptContext* context, ScriptEngine* engine) { QString message; bool condition = false; for (int i = 0; i < context->argumentCount(); i++) { if (i == 0) { - condition = context->argument(i).toBool(); // accept first value as condition + condition = context->argument(i)->toBool(); // accept first value as condition } else { - message += SPACE_SEPARATOR + context->argument(i).toString(); // accept other parameters as message + message += SPACE_SEPARATOR + context->argument(i)->toString(); // accept other parameters as message } } @@ -123,63 +126,64 @@ QScriptValue ConsoleScriptingInterface::assertion(QScriptContext* context, QScri } else { assertionResult = QString("Assertion failed : %1").arg(message); } - if (ScriptEngine* scriptEngine = qobject_cast(engine)) { - scriptEngine->scriptErrorMessage(assertionResult); + if (ScriptManager* scriptManager = engine->manager()) { + scriptManager->scriptErrorMessage(assertionResult); } } - return QScriptValue::NullValue; + return engine->nullValue(); } void ConsoleScriptingInterface::trace() { - if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->scriptPrintedMessage + ScriptEnginePointer scriptEngine = engine(); + if (ScriptManager* scriptManager = scriptEngine->manager()) { + scriptManager->scriptPrintedMessage (QString(STACK_TRACE_FORMAT).arg(LINE_SEPARATOR, scriptEngine->currentContext()->backtrace().join(LINE_SEPARATOR))); } } void ConsoleScriptingInterface::clear() { - if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->clearDebugLogWindow(); + if (ScriptManager* scriptManager = engine()->manager()) { + scriptManager->clearDebugLogWindow(); } } -QScriptValue ConsoleScriptingInterface::group(QScriptContext* context, QScriptEngine* engine) { - logGroupMessage(context->argument(0).toString(), engine); // accept first parameter as label - _groupDetails.push_back(context->argument(0).toString()); - return QScriptValue::NullValue; +ScriptValuePointer ConsoleScriptingInterface::group(ScriptContext* context, ScriptEngine* engine) { + logGroupMessage(context->argument(0)->toString(), engine); // accept first parameter as label + _groupDetails.push_back(context->argument(0)->toString()); + return engine->nullValue(); } -QScriptValue ConsoleScriptingInterface::groupCollapsed(QScriptContext* context, QScriptEngine* engine) { - logGroupMessage(context->argument(0).toString(), engine); // accept first parameter as label - _groupDetails.push_back(context->argument(0).toString()); - return QScriptValue::NullValue; +ScriptValuePointer ConsoleScriptingInterface::groupCollapsed(ScriptContext* context, ScriptEngine* engine) { + logGroupMessage(context->argument(0)->toString(), engine); // accept first parameter as label + _groupDetails.push_back(context->argument(0)->toString()); + return engine->nullValue(); } -QScriptValue ConsoleScriptingInterface::groupEnd(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer ConsoleScriptingInterface::groupEnd(ScriptContext* context, ScriptEngine* engine) { ConsoleScriptingInterface::_groupDetails.removeLast(); - return QScriptValue::NullValue; + return engine->nullValue(); } -QString ConsoleScriptingInterface::appendArguments(QScriptContext* context) { +QString ConsoleScriptingInterface::appendArguments(ScriptContext* context) { QString message; for (int i = 0; i < context->argumentCount(); i++) { if (i > 0) { message += SPACE_SEPARATOR; } - message += context->argument(i).toString(); + message += context->argument(i)->toString(); } return message; } -void ConsoleScriptingInterface::logGroupMessage(QString message, QScriptEngine* engine) { +void ConsoleScriptingInterface::logGroupMessage(QString message, ScriptEngine* engine) { int _addSpaces = _groupDetails.count() * INDENTATION; QString logMessage; for (int i = 0; i < _addSpaces; i++) { logMessage.append(SPACE_SEPARATOR); } logMessage.append(message); - if (ScriptEngine* scriptEngine = qobject_cast(engine)) { - scriptEngine->scriptPrintedMessage(logMessage); + if (ScriptManager* scriptManager = engine->manager()) { + scriptManager->scriptPrintedMessage(logMessage); } } diff --git a/libraries/script-engine/src/ConsoleScriptingInterface.h b/libraries/script-engine/src/ConsoleScriptingInterface.h index 7eec44d1037..82fbfc9e410 100644 --- a/libraries/script-engine/src/ConsoleScriptingInterface.h +++ b/libraries/script-engine/src/ConsoleScriptingInterface.h @@ -24,7 +24,14 @@ #include #include #include -#include +#include + +#include "Scriptable.h" + +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The console API provides program logging facilities. @@ -38,7 +45,7 @@ * @hifi-assignment-client */ // Scriptable interface of "console" object. Used exclusively in the JavaScript API -class ConsoleScriptingInterface : public QObject, protected QScriptable { +class ConsoleScriptingInterface : public QObject, protected Scriptable { Q_OBJECT public: @@ -48,7 +55,7 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * @function console.info * @param {...*} [message] - The message values to log. */ - static QScriptValue info(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer info(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Logs a message to the program log and triggers {@link Script.printedMessage}. @@ -66,7 +73,7 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * // string 7 true * // INFO - Console.log message: "string 7 true" in [console.js] */ - static QScriptValue log(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer log(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Logs a message to the program log and triggers {@link Script.printedMessage}. @@ -74,7 +81,7 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * @function console.debug * @param {...*} [message] - The message values to log. */ - static QScriptValue debug(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer debug(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Logs a "WARNING" message to the program log and triggers {@link Script.warningMessage}. @@ -82,7 +89,7 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * @function console.warn * @param {...*} [message] - The message values to log. */ - static QScriptValue warn(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer warn(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Logs an "ERROR" message to the program log and triggers {@link Script.errorMessage}. @@ -90,7 +97,7 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * @function console.error * @param {...*} [message] - The message values to log. */ - static QScriptValue error(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer error(ScriptContext* context, ScriptEngine* engine); /**jsdoc * A synonym of {@link console.error}. @@ -99,7 +106,7 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * @function console.exception * @param {...*} [message] - The message values to log. */ - static QScriptValue exception(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer exception(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Logs an "ERROR" message to the program log and triggers {@link Script.errorMessage}, if a test condition fails. @@ -122,7 +129,7 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * // INFO - Script continues running. */ // Note: Is registered in the script engine as "assert" - static QScriptValue assertion(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer assertion(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Logs a message to the program log and triggers {@link Script.printedMessage}, then starts indenting subsequent @@ -150,7 +157,7 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * // Sentence 5 * //Sentence 6 */ - static QScriptValue group(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer group(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Has the same behavior as {@link console.group}. @@ -159,13 +166,13 @@ class ConsoleScriptingInterface : public QObject, protected QScriptable { * @function console.groupCollapsed * @param {*} message - The message value to log. */ - static QScriptValue groupCollapsed(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer groupCollapsed(ScriptContext* context, ScriptEngine* engine); /**jsdoc * Finishes a group of indented {@link console.log} messages. * @function console.groupEnd */ - static QScriptValue groupEnd(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer groupEnd(ScriptContext* context, ScriptEngine* engine); public slots: @@ -215,8 +222,8 @@ public slots: private: QHash _timerDetails; static QList _groupDetails; - static void logGroupMessage(QString message, QScriptEngine* engine); - static QString appendArguments(QScriptContext* context); + static void logGroupMessage(QString message, ScriptEngine* engine); + static QString appendArguments(ScriptContext* context); }; #endif // hifi_ConsoleScriptingInterface_h diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index 94c074d44e1..2715d6252b5 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -13,16 +13,18 @@ #include "KeyEvent.h" #include "MouseEvent.h" -#include "SpatialEvent.h" #include "PointerEvent.h" +#include "ScriptEngine.h" +#include "ScriptEngineCast.h" +#include "SpatialEvent.h" #include "TouchEvent.h" #include "WheelEvent.h" -void registerEventTypes(QScriptEngine* engine) { - qScriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue); - qScriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue); - qScriptRegisterMetaType(engine, PointerEvent::toScriptValue, PointerEvent::fromScriptValue); - qScriptRegisterMetaType(engine, TouchEvent::toScriptValue, TouchEvent::fromScriptValue); - qScriptRegisterMetaType(engine, WheelEvent::toScriptValue, WheelEvent::fromScriptValue); - qScriptRegisterMetaType(engine, SpatialEvent::toScriptValue, SpatialEvent::fromScriptValue); +void registerEventTypes(ScriptEngine* engine) { + scriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue); + scriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue); + scriptRegisterMetaType(engine, PointerEvent::toScriptValue, PointerEvent::fromScriptValue); + scriptRegisterMetaType(engine, TouchEvent::toScriptValue, TouchEvent::fromScriptValue); + scriptRegisterMetaType(engine, WheelEvent::toScriptValue, WheelEvent::fromScriptValue); + scriptRegisterMetaType(engine, SpatialEvent::toScriptValue, SpatialEvent::fromScriptValue); } diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 146ab338d61..26128ea2ec4 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -12,8 +12,8 @@ #ifndef hifi_EventTypes_h #define hifi_EventTypes_h -#include +class ScriptEngine; -void registerEventTypes(QScriptEngine* engine); +void registerEventTypes(ScriptEngine* engine); #endif // hifi_EventTypes_h diff --git a/libraries/script-engine/src/KeyEvent.cpp b/libraries/script-engine/src/KeyEvent.cpp index 1887486054f..598fd19a355 100644 --- a/libraries/script-engine/src/KeyEvent.cpp +++ b/libraries/script-engine/src/KeyEvent.cpp @@ -12,9 +12,10 @@ #include "KeyEvent.h" #include -#include #include "ScriptEngineLogging.h" +#include "ScriptEngine.h" +#include "ScriptValue.h" KeyEvent::KeyEvent() : key(0), @@ -173,37 +174,37 @@ KeyEvent::operator QKeySequence() const { * print(JSON.stringify(event)); * }); */ -QScriptValue KeyEvent::toScriptValue(QScriptEngine* engine, const KeyEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty("key", event.key); - obj.setProperty("text", event.text); - obj.setProperty("isShifted", event.isShifted); - obj.setProperty("isMeta", event.isMeta); - obj.setProperty("isControl", event.isControl); - obj.setProperty("isAlt", event.isAlt); - obj.setProperty("isKeypad", event.isKeypad); - obj.setProperty("isAutoRepeat", event.isAutoRepeat); +ScriptValuePointer KeyEvent::toScriptValue(ScriptEngine* engine, const KeyEvent& event) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("key", event.key); + obj->setProperty("text", event.text); + obj->setProperty("isShifted", event.isShifted); + obj->setProperty("isMeta", event.isMeta); + obj->setProperty("isControl", event.isControl); + obj->setProperty("isAlt", event.isAlt); + obj->setProperty("isKeypad", event.isKeypad); + obj->setProperty("isAutoRepeat", event.isAutoRepeat); return obj; } -void KeyEvent::fromScriptValue(const QScriptValue& object, KeyEvent& event) { +void KeyEvent::fromScriptValue(const ScriptValuePointer& object, KeyEvent& event) { event.isValid = false; // assume the worst - event.isMeta = object.property("isMeta").toVariant().toBool(); - event.isControl = object.property("isControl").toVariant().toBool(); - event.isAlt = object.property("isAlt").toVariant().toBool(); - event.isKeypad = object.property("isKeypad").toVariant().toBool(); - event.isAutoRepeat = object.property("isAutoRepeat").toVariant().toBool(); + event.isMeta = object->property("isMeta")->toVariant().toBool(); + event.isControl = object->property("isControl")->toVariant().toBool(); + event.isAlt = object->property("isAlt")->toVariant().toBool(); + event.isKeypad = object->property("isKeypad")->toVariant().toBool(); + event.isAutoRepeat = object->property("isAutoRepeat")->toVariant().toBool(); - QScriptValue key = object.property("key"); - if (key.isValid()) { - event.key = key.toVariant().toInt(); + ScriptValuePointer key = object->property("key"); + if (key->isValid()) { + event.key = key->toVariant().toInt(); event.text = QString(QChar(event.key)); event.isValid = true; } else { - QScriptValue text = object.property("text"); - if (text.isValid()) { - event.text = object.property("text").toVariant().toString(); + ScriptValuePointer text = object->property("text"); + if (text->isValid()) { + event.text = object->property("text")->toVariant().toString(); // if the text is a special command, then map it here... // TODO: come up with more elegant solution here, a map? is there a Qt function that gives nice names for keys? @@ -282,9 +283,9 @@ void KeyEvent::fromScriptValue(const QScriptValue& object, KeyEvent& event) { } } - QScriptValue isShifted = object.property("isShifted"); - if (isShifted.isValid()) { - event.isShifted = isShifted.toVariant().toBool(); + ScriptValuePointer isShifted = object->property("isShifted"); + if (isShifted->isValid()) { + event.isShifted = isShifted->toVariant().toBool(); } else { // if no isShifted was included, get it from the text QChar character = event.text.at(0); diff --git a/libraries/script-engine/src/KeyEvent.h b/libraries/script-engine/src/KeyEvent.h index 4d66192a74f..237317bafd1 100644 --- a/libraries/script-engine/src/KeyEvent.h +++ b/libraries/script-engine/src/KeyEvent.h @@ -13,7 +13,11 @@ #define hifi_KeyEvent_h #include -#include +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class KeyEvent { public: @@ -22,8 +26,8 @@ class KeyEvent { bool operator==(const KeyEvent& other) const; operator QKeySequence() const; - static QScriptValue toScriptValue(QScriptEngine* engine, const KeyEvent& event); - static void fromScriptValue(const QScriptValue& object, KeyEvent& event); + static ScriptValuePointer toScriptValue(ScriptEngine* engine, const KeyEvent& event); + static void fromScriptValue(const ScriptValuePointer& object, KeyEvent& event); int key; QString text; diff --git a/libraries/script-engine/src/MIDIEvent.cpp b/libraries/script-engine/src/MIDIEvent.cpp index b32c5d9d87e..fb782d07fb6 100644 --- a/libraries/script-engine/src/MIDIEvent.cpp +++ b/libraries/script-engine/src/MIDIEvent.cpp @@ -11,8 +11,14 @@ #include "MIDIEvent.h" -void registerMIDIMetaTypes(QScriptEngine* engine) { - qScriptRegisterMetaType(engine, midiEventToScriptValue, midiEventFromScriptValue); +#include + +#include "ScriptEngine.h" +#include "ScriptEngineCast.h" +#include "ScriptValue.h" + +void registerMIDIMetaTypes(ScriptEngine* engine) { + scriptRegisterMetaType(engine, midiEventToScriptValue, midiEventFromScriptValue); } const QString MIDI_DELTA_TIME_PROP_NAME = "deltaTime"; @@ -20,18 +26,18 @@ const QString MIDI_EVENT_TYPE_PROP_NAME = "type"; const QString MIDI_DATA_1_PROP_NAME = "data1"; const QString MIDI_DATA_2_PROP_NAME = "data2"; -QScriptValue midiEventToScriptValue(QScriptEngine* engine, const MIDIEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty(MIDI_DELTA_TIME_PROP_NAME, event.deltaTime); - obj.setProperty(MIDI_EVENT_TYPE_PROP_NAME, event.type); - obj.setProperty(MIDI_DATA_1_PROP_NAME, event.data1); - obj.setProperty(MIDI_DATA_2_PROP_NAME, event.data2); +ScriptValuePointer midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty(MIDI_DELTA_TIME_PROP_NAME, event.deltaTime); + obj->setProperty(MIDI_EVENT_TYPE_PROP_NAME, event.type); + obj->setProperty(MIDI_DATA_1_PROP_NAME, event.data1); + obj->setProperty(MIDI_DATA_2_PROP_NAME, event.data2); return obj; } -void midiEventFromScriptValue(const QScriptValue &object, MIDIEvent& event) { - event.deltaTime = object.property(MIDI_DELTA_TIME_PROP_NAME).toVariant().toDouble(); - event.type = object.property(MIDI_EVENT_TYPE_PROP_NAME).toVariant().toUInt(); - event.data1 = object.property(MIDI_DATA_1_PROP_NAME).toVariant().toUInt(); - event.data2 = object.property(MIDI_DATA_2_PROP_NAME).toVariant().toUInt(); +void midiEventFromScriptValue(const ScriptValuePointer &object, MIDIEvent& event) { + event.deltaTime = object->property(MIDI_DELTA_TIME_PROP_NAME)->toVariant().toDouble(); + event.type = object->property(MIDI_EVENT_TYPE_PROP_NAME)->toVariant().toUInt(); + event.data1 = object->property(MIDI_DATA_1_PROP_NAME)->toVariant().toUInt(); + event.data2 = object->property(MIDI_DATA_2_PROP_NAME)->toVariant().toUInt(); } \ No newline at end of file diff --git a/libraries/script-engine/src/MIDIEvent.h b/libraries/script-engine/src/MIDIEvent.h index 6bf4a4b72b3..716b8c535eb 100644 --- a/libraries/script-engine/src/MIDIEvent.h +++ b/libraries/script-engine/src/MIDIEvent.h @@ -9,11 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #ifndef hifi_MIDIEvent_h #define hifi_MIDIEvent_h +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + class MIDIEvent { public: double deltaTime; @@ -24,9 +28,9 @@ class MIDIEvent { Q_DECLARE_METATYPE(MIDIEvent) -void registerMIDIMetaTypes(QScriptEngine* engine); +void registerMIDIMetaTypes(ScriptEngine* engine); -QScriptValue midiEventToScriptValue(QScriptEngine* engine, const MIDIEvent& event); -void midiEventFromScriptValue(const QScriptValue &object, MIDIEvent& event); +ScriptValuePointer midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event); +void midiEventFromScriptValue(const ScriptValuePointer &object, MIDIEvent& event); #endif // hifi_MIDIEvent_h \ No newline at end of file diff --git a/libraries/script-engine/src/Mat4.cpp b/libraries/script-engine/src/Mat4.cpp index d4d73a46ccd..755744777da 100644 --- a/libraries/script-engine/src/Mat4.cpp +++ b/libraries/script-engine/src/Mat4.cpp @@ -20,6 +20,7 @@ #include "ScriptEngineLogging.h" #include "ScriptEngine.h" +#include "ScriptManager.h" glm::mat4 Mat4::multiply(const glm::mat4& m1, const glm::mat4& m2) const { return m1 * m2; @@ -87,7 +88,7 @@ void Mat4::print(const QString& label, const glm::mat4& m, bool transpose) const QString message = QString("%1 %2").arg(qPrintable(label)); message = message.arg(glm::to_string(out).c_str()); qCDebug(scriptengine) << message; - if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->print(message); + if (ScriptManager* scriptManager = engine()->manager()) { + scriptManager->print(message); } } diff --git a/libraries/script-engine/src/Mat4.h b/libraries/script-engine/src/Mat4.h index 33fd8895413..d8004b9b8b0 100644 --- a/libraries/script-engine/src/Mat4.h +++ b/libraries/script-engine/src/Mat4.h @@ -16,10 +16,10 @@ #include #include -#include #include #include #include "RegisteredMetaTypes.h" +#include "Scriptable.h" /**jsdoc * The Mat4 API provides facilities for generating and using 4 x 4 matrices. These matrices are typically used to @@ -37,7 +37,7 @@ */ /// Scriptable Mat4 object. Used exclusively in the JavaScript API -class Mat4 : public QObject, protected QScriptable { +class Mat4 : public QObject, protected Scriptable { Q_OBJECT public slots: diff --git a/libraries/script-engine/src/MenuItemProperties.cpp b/libraries/script-engine/src/MenuItemProperties.cpp index af9c4a3d0ab..0d863552461 100644 --- a/libraries/script-engine/src/MenuItemProperties.cpp +++ b/libraries/script-engine/src/MenuItemProperties.cpp @@ -14,6 +14,9 @@ #include #include +#include "ScriptEngine.h" +#include "ScriptEngineCast.h" +#include "ScriptValue.h" MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& menuItemName, const QString& shortcutKey, bool checkable, bool checked, bool separator) : @@ -40,12 +43,12 @@ MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& m { } -void registerMenuItemProperties(QScriptEngine* engine) { - qScriptRegisterMetaType(engine, menuItemPropertiesToScriptValue, menuItemPropertiesFromScriptValue); +void registerMenuItemProperties(ScriptEngine* engine) { + scriptRegisterMetaType(engine, menuItemPropertiesToScriptValue, menuItemPropertiesFromScriptValue); } -QScriptValue menuItemPropertiesToScriptValue(QScriptEngine* engine, const MenuItemProperties& properties) { - QScriptValue obj = engine->newObject(); +ScriptValuePointer menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItemProperties& properties) { + ScriptValuePointer obj = engine->newObject(); // not supported return obj; } @@ -70,32 +73,32 @@ QScriptValue menuItemPropertiesToScriptValue(QScriptEngine* engine, const MenuIt * @property {string} [afterItem] - The name of the menu item to place this menu item after. * @property {string} [grouping] - The name of grouping to add this menu item to. */ -void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemProperties& properties) { - properties.menuName = object.property("menuName").toVariant().toString(); - properties.menuItemName = object.property("menuItemName").toVariant().toString(); - properties.isCheckable = object.property("isCheckable").toVariant().toBool(); - properties.isChecked = object.property("isChecked").toVariant().toBool(); - properties.isSeparator = object.property("isSeparator").toVariant().toBool(); +void menuItemPropertiesFromScriptValue(const ScriptValuePointer& object, MenuItemProperties& properties) { + properties.menuName = object->property("menuName")->toVariant().toString(); + properties.menuItemName = object->property("menuItemName")->toVariant().toString(); + properties.isCheckable = object->property("isCheckable")->toVariant().toBool(); + properties.isChecked = object->property("isChecked")->toVariant().toBool(); + properties.isSeparator = object->property("isSeparator")->toVariant().toBool(); // handle the shortcut key options in order... - QScriptValue shortcutKeyValue = object.property("shortcutKey"); - if (shortcutKeyValue.isValid()) { - properties.shortcutKey = shortcutKeyValue.toVariant().toString(); + ScriptValuePointer shortcutKeyValue = object->property("shortcutKey"); + if (shortcutKeyValue->isValid()) { + properties.shortcutKey = shortcutKeyValue->toVariant().toString(); properties.shortcutKeySequence = properties.shortcutKey; } else { - QScriptValue shortcutKeyEventValue = object.property("shortcutKeyEvent"); - if (shortcutKeyEventValue.isValid()) { + ScriptValuePointer shortcutKeyEventValue = object->property("shortcutKeyEvent"); + if (shortcutKeyEventValue->isValid()) { KeyEvent::fromScriptValue(shortcutKeyEventValue, properties.shortcutKeyEvent); properties.shortcutKeySequence = properties.shortcutKeyEvent; } } - if (object.property("position").isValid()) { - properties.position = object.property("position").toVariant().toInt(); + if (object->property("position")->isValid()) { + properties.position = object->property("position")->toVariant().toInt(); } - properties.beforeItem = object.property("beforeItem").toVariant().toString(); - properties.afterItem = object.property("afterItem").toVariant().toString(); - properties.grouping = object.property("grouping").toVariant().toString(); + properties.beforeItem = object->property("beforeItem")->toVariant().toString(); + properties.afterItem = object->property("afterItem")->toVariant().toString(); + properties.grouping = object->property("grouping")->toVariant().toString(); } diff --git a/libraries/script-engine/src/MenuItemProperties.h b/libraries/script-engine/src/MenuItemProperties.h index 9de43378383..1422b784227 100644 --- a/libraries/script-engine/src/MenuItemProperties.h +++ b/libraries/script-engine/src/MenuItemProperties.h @@ -12,10 +12,13 @@ #ifndef hifi_MenuItemProperties_h #define hifi_MenuItemProperties_h -#include - #include "KeyEvent.h" +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class MenuItemProperties { public: @@ -49,9 +52,9 @@ class MenuItemProperties { static const int UNSPECIFIED_POSITION = -1; }; Q_DECLARE_METATYPE(MenuItemProperties) -QScriptValue menuItemPropertiesToScriptValue(QScriptEngine* engine, const MenuItemProperties& props); -void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemProperties& props); -void registerMenuItemProperties(QScriptEngine* engine); +ScriptValuePointer menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItemProperties& props); +void menuItemPropertiesFromScriptValue(const ScriptValuePointer& object, MenuItemProperties& props); +void registerMenuItemProperties(ScriptEngine* engine); diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index 2e9a9ca14a9..a9b72db8cb7 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -10,20 +10,20 @@ // #include "ModelScriptingInterface.h" -#include -#include -#include #include #include "ScriptEngine.h" +#include "ScriptEngineCast.h" #include "ScriptEngineLogging.h" +#include "ScriptManager.h" +#include "ScriptValueUtils.h" #include "OBJWriter.h" ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) { - _modelScriptEngine = qobject_cast(parent); + _modelScriptEngine = qobject_cast(parent)->engine(); - qScriptRegisterSequenceMetaType>(_modelScriptEngine); - qScriptRegisterMetaType(_modelScriptEngine, meshFaceToScriptValue, meshFaceFromScriptValue); - qScriptRegisterMetaType(_modelScriptEngine, qVectorMeshFaceToScriptValue, qVectorMeshFaceFromScriptValue); + scriptRegisterSequenceMetaType>(_modelScriptEngine.get()); + scriptRegisterMetaType(_modelScriptEngine.get(), meshFaceToScriptValue, meshFaceFromScriptValue); + scriptRegisterMetaType(_modelScriptEngine.get(), qVectorMeshFaceToScriptValue, qVectorMeshFaceFromScriptValue); } QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { @@ -35,7 +35,7 @@ QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { return writeOBJToString(meshes); } -QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { +ScriptValuePointer ModelScriptingInterface::appendMeshes(MeshProxyList in) { // figure out the size of the resulting mesh size_t totalVertexCount { 0 }; size_t totalColorCount { 0 }; @@ -140,16 +140,16 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { MeshProxy* resultProxy = new SimpleMeshProxy(result); - return meshToScriptValue(_modelScriptEngine, resultProxy); + return meshToScriptValue(_modelScriptEngine.get(), resultProxy); } -QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { +ScriptValuePointer ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { if (!meshProxy) { - return QScriptValue(false); + return ScriptValuePointer(false); } MeshPointer mesh = meshProxy->getMeshPointer(); if (!mesh) { - return QScriptValue(false); + return ScriptValuePointer(false); } const auto inverseTransposeTransform = glm::inverse(glm::transpose(transform)); @@ -158,45 +158,45 @@ QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshPro [&](glm::vec3 normal){ return glm::vec3(inverseTransposeTransform * glm::vec4(normal, 0.0f)); }, [&](uint32_t index){ return index; }); MeshProxy* resultProxy = new SimpleMeshProxy(result); - return meshToScriptValue(_modelScriptEngine, resultProxy); + return meshToScriptValue(_modelScriptEngine.get(), resultProxy); } -QScriptValue ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) { +ScriptValuePointer ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) { if (!meshProxy) { - return QScriptValue(false); + return ScriptValuePointer(false); } MeshPointer mesh = meshProxy->getMeshPointer(); if (!mesh) { - return QScriptValue(false); + return ScriptValuePointer(false); } gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); - return numVertices; + return _modelScriptEngine->newValue(numVertices); } -QScriptValue ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int vertexIndex) { +ScriptValuePointer ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int vertexIndex) { if (!meshProxy) { - return QScriptValue(false); + return ScriptValuePointer(false); } MeshPointer mesh = meshProxy->getMeshPointer(); if (!mesh) { - return QScriptValue(false); + return ScriptValuePointer(false); } const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); if (vertexIndex < 0 || vertexIndex >= numVertices) { - return QScriptValue(false); + return ScriptValuePointer(false); } glm::vec3 pos = vertexBufferView.get(vertexIndex); - return vec3ToScriptValue(_modelScriptEngine, pos); + return vec3ToScriptValue(_modelScriptEngine.get(), pos); } -QScriptValue ModelScriptingInterface::newMesh(const QVector& vertices, +ScriptValuePointer ModelScriptingInterface::newMesh(const QVector& vertices, const QVector& normals, const QVector& faces) { graphics::MeshPointer mesh(new graphics::Mesh()); @@ -247,5 +247,5 @@ QScriptValue ModelScriptingInterface::newMesh(const QVector& vertices MeshProxy* meshProxy = new SimpleMeshProxy(mesh); - return meshToScriptValue(_modelScriptEngine, meshProxy); + return meshToScriptValue(_modelScriptEngine.get(), meshProxy); } diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/script-engine/src/ModelScriptingInterface.h index 39170bb370b..4ba9f5ff133 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.h +++ b/libraries/script-engine/src/ModelScriptingInterface.h @@ -13,9 +13,14 @@ #define hifi_ModelScriptingInterface_h #include +#include #include -class QScriptEngine; + +class ScriptEngine; +class ScriptValue; +using ScriptEnginePointer = QSharedPointer; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The Model API provides the ability to manipulate meshes. You can get the meshes for an entity using @@ -52,7 +57,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshProxy[]} meshes - The meshes to combine. * @returns {MeshProxy} The combined mesh. */ - Q_INVOKABLE QScriptValue appendMeshes(MeshProxyList in); + Q_INVOKABLE ScriptValuePointer appendMeshes(MeshProxyList in); /**jsdoc * Transforms the vertices in a mesh. @@ -61,7 +66,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshProxy} mesh - The mesh to apply the transform to. * @returns {MeshProxy|boolean} The transformed mesh, if valid. false if an error. */ - Q_INVOKABLE QScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy); + Q_INVOKABLE ScriptValuePointer transformMesh(glm::mat4 transform, MeshProxy* meshProxy); /**jsdoc * Creates a new mesh. @@ -71,7 +76,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshFace[]} faces - The faces in the mesh. * @returns {MeshProxy} A new mesh. */ - Q_INVOKABLE QScriptValue newMesh(const QVector& vertices, + Q_INVOKABLE ScriptValuePointer newMesh(const QVector& vertices, const QVector& normals, const QVector& faces); @@ -81,7 +86,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshProxy} mesh - The mesh to count the vertices in. * @returns {number|boolean} The number of vertices in the mesh, if valid. false if an error. */ - Q_INVOKABLE QScriptValue getVertexCount(MeshProxy* meshProxy); + Q_INVOKABLE ScriptValuePointer getVertexCount(MeshProxy* meshProxy); /**jsdoc * Gets the position of a vertex in a mesh. @@ -90,10 +95,10 @@ class ModelScriptingInterface : public QObject { * @param {number} index - The index of the vertex to get. * @returns {Vec3|boolean} The local position of the vertex relative to the mesh, if valid. false if an error. */ - Q_INVOKABLE QScriptValue getVertex(MeshProxy* meshProxy, int vertexIndex); + Q_INVOKABLE ScriptValuePointer getVertex(MeshProxy* meshProxy, int vertexIndex); private: - QScriptEngine* _modelScriptEngine { nullptr }; + ScriptEnginePointer _modelScriptEngine { nullptr }; }; #endif // hifi_ModelScriptingInterface_h diff --git a/libraries/script-engine/src/MouseEvent.cpp b/libraries/script-engine/src/MouseEvent.cpp index f3a5cb80c05..218f675ef5c 100644 --- a/libraries/script-engine/src/MouseEvent.cpp +++ b/libraries/script-engine/src/MouseEvent.cpp @@ -11,8 +11,8 @@ #include "MouseEvent.h" -#include -#include +#include "ScriptEngine.h" +#include "ScriptValue.h" MouseEvent::MouseEvent() : x(0.0f), @@ -86,22 +86,22 @@ MouseEvent::MouseEvent(const QMouseEvent& event) : * print(JSON.stringify(event)); * }); */ -QScriptValue MouseEvent::toScriptValue(QScriptEngine* engine, const MouseEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", event.x); - obj.setProperty("y", event.y); - obj.setProperty("button", event.button); - obj.setProperty("isLeftButton", event.isLeftButton); - obj.setProperty("isRightButton", event.isRightButton); - obj.setProperty("isMiddleButton", event.isMiddleButton); - obj.setProperty("isShifted", event.isShifted); - obj.setProperty("isMeta", event.isMeta); - obj.setProperty("isControl", event.isControl); - obj.setProperty("isAlt", event.isAlt); +ScriptValuePointer MouseEvent::toScriptValue(ScriptEngine* engine, const MouseEvent& event) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("x", event.x); + obj->setProperty("y", event.y); + obj->setProperty("button", event.button); + obj->setProperty("isLeftButton", event.isLeftButton); + obj->setProperty("isRightButton", event.isRightButton); + obj->setProperty("isMiddleButton", event.isMiddleButton); + obj->setProperty("isShifted", event.isShifted); + obj->setProperty("isMeta", event.isMeta); + obj->setProperty("isControl", event.isControl); + obj->setProperty("isAlt", event.isAlt); return obj; } -void MouseEvent::fromScriptValue(const QScriptValue& object, MouseEvent& event) { +void MouseEvent::fromScriptValue(const ScriptValuePointer& object, MouseEvent& event) { // nothing for now... } diff --git a/libraries/script-engine/src/MouseEvent.h b/libraries/script-engine/src/MouseEvent.h index 04e474366d6..a61d7d01660 100644 --- a/libraries/script-engine/src/MouseEvent.h +++ b/libraries/script-engine/src/MouseEvent.h @@ -13,19 +13,21 @@ #define hifi_MouseEvent_h #include -#include +#include -class QScriptEngine; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class MouseEvent { public: MouseEvent(); MouseEvent(const QMouseEvent& event); - static QScriptValue toScriptValue(QScriptEngine* engine, const MouseEvent& event); - static void fromScriptValue(const QScriptValue& object, MouseEvent& event); + static ScriptValuePointer toScriptValue(ScriptEngine* engine, const MouseEvent& event); + static void fromScriptValue(const ScriptValuePointer& object, MouseEvent& event); - QScriptValue toScriptValue(QScriptEngine* engine) const { return MouseEvent::toScriptValue(engine, *this); } + ScriptValuePointer toScriptValue(ScriptEngine* engine) const { return MouseEvent::toScriptValue(engine, *this); } int x; int y; diff --git a/libraries/shared/src/PointerEvent.cpp b/libraries/script-engine/src/PointerEvent.cpp similarity index 72% rename from libraries/shared/src/PointerEvent.cpp rename to libraries/script-engine/src/PointerEvent.cpp index 6882efd5886..d5fc771f5f3 100644 --- a/libraries/shared/src/PointerEvent.cpp +++ b/libraries/script-engine/src/PointerEvent.cpp @@ -11,10 +11,10 @@ #include "PointerEvent.h" -#include -#include - #include "RegisteredMetaTypes.h" +#include "ScriptEngine.h" +#include "ScriptValue.h" +#include "ScriptValueUtils.h" static bool areFlagsSet(uint32_t flags, uint32_t mask) { return (flags & mask) != 0; @@ -125,97 +125,97 @@ void PointerEvent::setButton(Button button) { * * @typedef {number} KeyboardModifiers */ -QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEvent& event) { - QScriptValue obj = engine->newObject(); +ScriptValuePointer PointerEvent::toScriptValue(ScriptEngine* engine, const PointerEvent& event) { + ScriptValuePointer obj = engine->newObject(); switch (event._type) { case Press: - obj.setProperty("type", "Press"); + obj->setProperty("type", "Press"); break; case DoublePress: - obj.setProperty("type", "DoublePress"); + obj->setProperty("type", "DoublePress"); break; case Release: - obj.setProperty("type", "Release"); + obj->setProperty("type", "Release"); break; default: case Move: - obj.setProperty("type", "Move"); + obj->setProperty("type", "Move"); break; }; - obj.setProperty("id", event._id); + obj->setProperty("id", event._id); - QScriptValue pos2D = engine->newObject(); - pos2D.setProperty("x", event._pos2D.x); - pos2D.setProperty("y", event._pos2D.y); - obj.setProperty("pos2D", pos2D); + ScriptValuePointer pos2D = engine->newObject(); + pos2D->setProperty("x", event._pos2D.x); + pos2D->setProperty("y", event._pos2D.y); + obj->setProperty("pos2D", pos2D); - QScriptValue pos3D = engine->newObject(); - pos3D.setProperty("x", event._pos3D.x); - pos3D.setProperty("y", event._pos3D.y); - pos3D.setProperty("z", event._pos3D.z); - obj.setProperty("pos3D", pos3D); + ScriptValuePointer pos3D = engine->newObject(); + pos3D->setProperty("x", event._pos3D.x); + pos3D->setProperty("y", event._pos3D.y); + pos3D->setProperty("z", event._pos3D.z); + obj->setProperty("pos3D", pos3D); - QScriptValue normal = engine->newObject(); - normal.setProperty("x", event._normal.x); - normal.setProperty("y", event._normal.y); - normal.setProperty("z", event._normal.z); - obj.setProperty("normal", normal); + ScriptValuePointer normal = engine->newObject(); + normal->setProperty("x", event._normal.x); + normal->setProperty("y", event._normal.y); + normal->setProperty("z", event._normal.z); + obj->setProperty("normal", normal); - QScriptValue direction = engine->newObject(); - direction.setProperty("x", event._direction.x); - direction.setProperty("y", event._direction.y); - direction.setProperty("z", event._direction.z); - obj.setProperty("direction", direction); + ScriptValuePointer direction = engine->newObject(); + direction->setProperty("x", event._direction.x); + direction->setProperty("y", event._direction.y); + direction->setProperty("z", event._direction.z); + obj->setProperty("direction", direction); bool isPrimaryButton = false; bool isSecondaryButton = false; bool isTertiaryButton = false; switch (event._button) { case NoButtons: - obj.setProperty("button", "None"); + obj->setProperty("button", "None"); break; case PrimaryButton: - obj.setProperty("button", "Primary"); + obj->setProperty("button", "Primary"); isPrimaryButton = true; break; case SecondaryButton: - obj.setProperty("button", "Secondary"); + obj->setProperty("button", "Secondary"); isSecondaryButton = true; break; case TertiaryButton: - obj.setProperty("button", "Tertiary"); + obj->setProperty("button", "Tertiary"); isTertiaryButton = true; break; } if (isPrimaryButton) { - obj.setProperty("isPrimaryButton", isPrimaryButton); - obj.setProperty("isLeftButton", isPrimaryButton); + obj->setProperty("isPrimaryButton", isPrimaryButton); + obj->setProperty("isLeftButton", isPrimaryButton); } if (isSecondaryButton) { - obj.setProperty("isSecondaryButton", isSecondaryButton); - obj.setProperty("isRightButton", isSecondaryButton); + obj->setProperty("isSecondaryButton", isSecondaryButton); + obj->setProperty("isRightButton", isSecondaryButton); } if (isTertiaryButton) { - obj.setProperty("isTertiaryButton", isTertiaryButton); - obj.setProperty("isMiddleButton", isTertiaryButton); + obj->setProperty("isTertiaryButton", isTertiaryButton); + obj->setProperty("isMiddleButton", isTertiaryButton); } - obj.setProperty("isPrimaryHeld", areFlagsSet(event._buttons, PrimaryButton)); - obj.setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton)); - obj.setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton)); + obj->setProperty("isPrimaryHeld", areFlagsSet(event._buttons, PrimaryButton)); + obj->setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton)); + obj->setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton)); - obj.setProperty("keyboardModifiers", QScriptValue(event.getKeyboardModifiers())); + obj->setProperty("keyboardModifiers", engine->newValue(event.getKeyboardModifiers())); return obj; } -void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& event) { - if (object.isObject()) { - QScriptValue type = object.property("type"); - QString typeStr = type.isString() ? type.toString() : "Move"; +void PointerEvent::fromScriptValue(const ScriptValuePointer& object, PointerEvent& event) { + if (object->isObject()) { + ScriptValuePointer type = object->property("type"); + QString typeStr = type->isString() ? type->toString() : "Move"; if (typeStr == "Press") { event._type = Press; } else if (typeStr == "DoublePress") { @@ -226,16 +226,16 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve event._type = Move; } - QScriptValue id = object.property("id"); - event._id = id.isNumber() ? (uint32_t)id.toNumber() : 0; + ScriptValuePointer id = object->property("id"); + event._id = id->isNumber() ? (uint32_t)id->toNumber() : 0; - vec2FromScriptValue(object.property("pos2D"), event._pos2D); - vec3FromScriptValue(object.property("pos3D"), event._pos3D); - vec3FromScriptValue(object.property("normal"), event._normal); - vec3FromScriptValue(object.property("direction"), event._direction); + vec2FromScriptValue(object->property("pos2D"), event._pos2D); + vec3FromScriptValue(object->property("pos3D"), event._pos3D); + vec3FromScriptValue(object->property("normal"), event._normal); + vec3FromScriptValue(object->property("direction"), event._direction); - QScriptValue button = object.property("button"); - QString buttonStr = type.isString() ? button.toString() : "NoButtons"; + ScriptValuePointer button = object->property("button"); + QString buttonStr = type->isString() ? button->toString() : "NoButtons"; if (buttonStr == "Primary") { event._button = PrimaryButton; @@ -247,9 +247,9 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve event._button = NoButtons; } - bool primary = object.property("isPrimaryHeld").toBool(); - bool secondary = object.property("isSecondaryHeld").toBool(); - bool tertiary = object.property("isTertiaryHeld").toBool(); + bool primary = object->property("isPrimaryHeld")->toBool(); + bool secondary = object->property("isSecondaryHeld")->toBool(); + bool tertiary = object->property("isTertiaryHeld")->toBool(); event._buttons = 0; if (primary) { event._buttons |= PrimaryButton; @@ -261,7 +261,7 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve event._buttons |= TertiaryButton; } - event._keyboardModifiers = (Qt::KeyboardModifiers)(object.property("keyboardModifiers").toUInt32()); + event._keyboardModifiers = (Qt::KeyboardModifiers)(object->property("keyboardModifiers")->toUInt32()); } } diff --git a/libraries/shared/src/PointerEvent.h b/libraries/script-engine/src/PointerEvent.h similarity index 89% rename from libraries/shared/src/PointerEvent.h rename to libraries/script-engine/src/PointerEvent.h index ea774aa67b1..197b144bdba 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/script-engine/src/PointerEvent.h @@ -16,7 +16,11 @@ #include #include -#include +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class PointerEvent { public: @@ -44,10 +48,10 @@ class PointerEvent { const glm::vec3& normal, const glm::vec3& direction, Button button = NoButtons, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::NoModifier); - static QScriptValue toScriptValue(QScriptEngine* engine, const PointerEvent& event); - static void fromScriptValue(const QScriptValue& object, PointerEvent& event); + static ScriptValuePointer toScriptValue(ScriptEngine* engine, const PointerEvent& event); + static void fromScriptValue(const ScriptValuePointer& object, PointerEvent& event); - QScriptValue toScriptValue(QScriptEngine* engine) const { return PointerEvent::toScriptValue(engine, *this); } + ScriptValuePointer toScriptValue(ScriptEngine* engine) const { return PointerEvent::toScriptValue(engine, *this); } EventType getType() const { return _type; } uint32_t getID() const { return _id; } diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 8335cb9adfc..724ad34416c 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -18,6 +18,7 @@ #include "ScriptEngineLogging.h" #include "ScriptEngine.h" +#include "ScriptManager.h" quat Quat::normalize(const glm::quat& q) { return glm::normalize(q); @@ -123,8 +124,8 @@ void Quat::print(const QString& label, const glm::quat& q, bool asDegrees) { message = message.arg(glm::to_string(glm::dquat(q)).c_str()); } qCDebug(scriptengine) << message; - if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->print(message); + if (ScriptManager* scriptManager = engine()->manager()) { + scriptManager->print(message); } } diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index c1eaa977971..2cba09a124a 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -18,10 +18,11 @@ #include #include -#include #include +#include "Scriptable.h" + /**jsdoc * A quaternion value. See also the {@link Quat(0)|Quat} API. * @typedef {object} Quat @@ -53,7 +54,7 @@ */ /// Scriptable interface a Quaternion helper class object. Used exclusively in the JavaScript API -class Quat : public QObject, protected QScriptable { +class Quat : public QObject, protected Scriptable { Q_OBJECT Q_PROPERTY(glm::quat IDENTITY READ IDENTITY CONSTANT) diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index cbcf94662e2..e6cab50b240 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -27,7 +26,10 @@ #include #include +#include "ScriptEngine.h" #include "ScriptEngineLogging.h" +#include "ScriptManager.h" +#include "ScriptValue.h" using namespace recording; @@ -54,18 +56,19 @@ float RecordingScriptingInterface::playerLength() const { return _player->length(); } -void RecordingScriptingInterface::playClip(NetworkClipLoaderPointer clipLoader, const QString& url, QScriptValue callback) { +void RecordingScriptingInterface::playClip(NetworkClipLoaderPointer clipLoader, const QString& url, ScriptValuePointer callback) { _player->queueClip(clipLoader->getClip()); - if (callback.isFunction()) { - QScriptValueList args { true, url }; - callback.call(QScriptValue(), args); + if (callback->isFunction()) { + auto engine = callback->engine(); + ScriptValueList args{ engine->newValue(true), engine->newValue(url) }; + callback->call(ScriptValuePointer(), args); } } -void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue callback) { +void RecordingScriptingInterface::loadRecording(const QString& url, ScriptValuePointer callback) { if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "loadRecording", Q_ARG(const QString&, url), Q_ARG(QScriptValue, callback)); + BLOCKING_INVOKE_METHOD(this, "loadRecording", Q_ARG(const QString&, url), Q_ARG(ScriptValuePointer, callback)); return; } @@ -82,8 +85,14 @@ void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue auto weakClipLoader = clipLoader.toWeakRef(); + auto manager = callback->engine()->manager(); + if (!manager) { + qWarning() << "This script does not belong to a ScriptManager"; + return; + } + // when clip loaded, call the callback with the URL and success boolean - connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, callback.engine(), + connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, manager, [this, weakClipLoader, url, callback]() mutable { if (auto clipLoader = weakClipLoader.toStrongRef()) { @@ -97,12 +106,14 @@ void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue }); // when clip load fails, call the callback with the URL and failure boolean - connect(clipLoader.data(), &recording::NetworkClipLoader::failed, callback.engine(), [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable { + connect(clipLoader.data(), &recording::NetworkClipLoader::failed, manager, + [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable { qCDebug(scriptengine) << "Failed to load recording from\"" << url << '"'; - if (callback.isFunction()) { - QScriptValueList args { false, url }; - callback.call(QScriptValue(), args); + if (callback->isFunction()) { + auto engine = callback->engine(); + ScriptValueList args{ engine->newValue(false), engine->newValue(url) }; + callback->call(ScriptValuePointer(), args); } if (auto clipLoader = weakClipLoader.toStrongRef()) { @@ -248,8 +259,8 @@ void RecordingScriptingInterface::saveRecording(const QString& filename) { recording::Clip::toFile(filename, _lastClip); } -bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUrl) { - if (!getClipAtpUrl.isFunction()) { +bool RecordingScriptingInterface::saveRecordingToAsset(ScriptValuePointer getClipAtpUrl) { + if (!getClipAtpUrl->isFunction()) { qCWarning(scriptengine) << "The argument is not a function."; return false; } @@ -258,7 +269,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr bool result; BLOCKING_INVOKE_METHOD(this, "saveRecordingToAsset", Q_RETURN_ARG(bool, result), - Q_ARG(QScriptValue, getClipAtpUrl)); + Q_ARG(ScriptValuePointer, getClipAtpUrl)); return result; } @@ -267,9 +278,14 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr return false; } + auto manager = getClipAtpUrl->engine()->manager(); + if (!manager) { + qWarning() << "This script does not belong to a ScriptManager"; + return false; + } + if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip))) { - QObject::connect(upload, &AssetUpload::finished, - getClipAtpUrl.engine(), [=](AssetUpload* upload, const QString& hash) mutable { + QObject::connect(upload, &AssetUpload::finished, manager, [=](AssetUpload* upload, const QString& hash) mutable { QString clip_atp_url = ""; if (upload->getError() == AssetUpload::NoError) { @@ -280,9 +296,9 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr qCWarning(scriptengine) << "Error during the Asset upload."; } - QScriptValueList args; - args << clip_atp_url; - getClipAtpUrl.call(QScriptValue(), args); + ScriptValueList args; + args << getClipAtpUrl->engine()->newValue(clip_atp_url); + getClipAtpUrl->call(ScriptValuePointer(), args); }); upload->start(); return true; diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index fd9c2d64e65..457623576a0 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -13,15 +13,15 @@ #include #include +#include -#include #include #include #include #include -class QScriptEngine; -class QScriptValue; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * The Recording API makes and plays back recordings of voice and avatar movements. Playback may be done on a @@ -68,7 +68,7 @@ public slots: * }); * } */ - void loadRecording(const QString& url, QScriptValue callback = QScriptValue()); + void loadRecording(const QString& url, ScriptValuePointer callback = ScriptValuePointer()); /**jsdoc @@ -332,7 +332,7 @@ public slots: * } * }, 5000); */ - bool saveRecordingToAsset(QScriptValue getClipAtpUrl); + bool saveRecordingToAsset(ScriptValuePointer getClipAtpUrl); /**jsdoc * Loads the most recently made recording and plays it back on your avatar. @@ -365,7 +365,7 @@ public slots: QSet _clipLoaders; private: - void playClip(recording::NetworkClipLoaderPointer clipLoader, const QString& url, QScriptValue callback); + void playClip(recording::NetworkClipLoaderPointer clipLoader, const QString& url, ScriptValuePointer callback); }; #endif // hifi_RecordingScriptingInterface_h diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 66c3f2ee96c..e232eb4de43 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -12,7 +12,6 @@ #ifndef hifi_SceneScriptingInterface_h #define hifi_SceneScriptingInterface_h -#include #include /**jsdoc diff --git a/libraries/script-engine/src/ScriptAudioInjector.cpp b/libraries/script-engine/src/ScriptAudioInjector.cpp index 0e42ec31e70..324a463ef2f 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.cpp +++ b/libraries/script-engine/src/ScriptAudioInjector.cpp @@ -11,19 +11,21 @@ #include "ScriptAudioInjector.h" +#include "ScriptEngine.h" #include "ScriptEngineLogging.h" +#include "ScriptValue.h" -QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in) { +ScriptValuePointer injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in) { // The AudioScriptingInterface::playSound method can return null, so we need to account for that. if (!in) { - return QScriptValue(QScriptValue::NullValue); + return engine->nullValue(); } - return engine->newQObject(in, QScriptEngine::ScriptOwnership); + return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void injectorFromScriptValue(const QScriptValue& object, ScriptAudioInjector*& out) { - out = qobject_cast(object.toQObject()); +void injectorFromScriptValue(const ScriptValuePointer& object, ScriptAudioInjector*& out) { + out = qobject_cast(object->toQObject()); } ScriptAudioInjector::ScriptAudioInjector(const AudioInjectorPointer& injector) : diff --git a/libraries/script-engine/src/ScriptAudioInjector.h b/libraries/script-engine/src/ScriptAudioInjector.h index 5f086019de4..48e3f5c912e 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.h +++ b/libraries/script-engine/src/ScriptAudioInjector.h @@ -13,9 +13,14 @@ #define hifi_ScriptAudioInjector_h #include +#include #include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + /**jsdoc * Plays or "injects" the content of an audio file. * @@ -139,12 +144,12 @@ public slots: private: QWeakPointer _injector; - friend QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in); + friend ScriptValuePointer injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in); }; Q_DECLARE_METATYPE(ScriptAudioInjector*) -QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in); -void injectorFromScriptValue(const QScriptValue& object, ScriptAudioInjector*& out); +ScriptValuePointer injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in); +void injectorFromScriptValue(const ScriptValuePointer& object, ScriptAudioInjector*& out); #endif // hifi_ScriptAudioInjector_h diff --git a/libraries/script-engine/src/ScriptContext.h b/libraries/script-engine/src/ScriptContext.h new file mode 100644 index 00000000000..c3bec123c4e --- /dev/null +++ b/libraries/script-engine/src/ScriptContext.h @@ -0,0 +1,53 @@ +// +// ScriptContext.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/1/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptContext_h +#define hifi_ScriptContext_h + +#include +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; +using ScriptEnginePointer = QSharedPointer; + +class ScriptFunctionContext { +public: + enum FunctionType { + ScriptFunction = 0, + QtFunction = 1, + QtPropertyFunction = 2, + NativeFunction = 3, + }; + +public: + virtual QString fileName() const = 0; + virtual QString functionName() const = 0; + virtual FunctionType functionType() const = 0; + virtual int lineNumber() const = 0; +}; + +class ScriptContext { +public: + virtual int argumentCount() const = 0; + virtual ScriptValuePointer argument(int index) const = 0; + virtual QStringList backtrace() const = 0; + virtual ScriptValuePointer callee() const = 0; + virtual ScriptEnginePointer engine() const = 0; + virtual ScriptFunctionContext* functionContext() const = 0; + virtual ScriptContext* parentContext() const = 0; + virtual ScriptValuePointer thisObject() const = 0; + virtual ScriptValuePointer throwError(const QString& text) = 0; + virtual ScriptValuePointer throwValue(const ScriptValuePointer& value) = 0; +}; + +#endif // hifi_ScriptContext_h \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index a19e63a665c..7144c91a374 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -13,1010 +13,143 @@ #ifndef hifi_ScriptEngine_h #define hifi_ScriptEngine_h -#include -#include - +#include #include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "PointerEvent.h" -#include "ArrayBufferClass.h" -#include "AssetScriptingInterface.h" -#include "AudioScriptingInterface.h" -#include "BaseScriptEngine.h" -#include "ExternalResource.h" -#include "Quat.h" -#include "Mat4.h" -#include "ScriptCache.h" -#include "ScriptUUID.h" -#include "Vec3.h" -#include "ConsoleScriptingInterface.h" -#include "SettingHandle.h" -#include "Profile.h" - -class QScriptEngineDebugger; - -static const QString NO_SCRIPT(""); - -static const int SCRIPT_FPS = 60; -static const int DEFAULT_MAX_ENTITY_PPS = 9000; -static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900; - -class ScriptEngines; +#include + +class QByteArray; +class QLatin1String; +class QString; +class QThread; +class QVariant; +class ScriptContext; +class ScriptEngine; +class ScriptManager; +class ScriptProgram; +class ScriptValue; +using ScriptEnginePointer = QSharedPointer; +using ScriptProgramPointer = QSharedPointer; +using ScriptValuePointer = QSharedPointer; Q_DECLARE_METATYPE(ScriptEnginePointer) -class CallbackData { +class ScriptEngine { public: - QScriptValue function; - EntityItemID definingEntityIdentifier; - QUrl definingSandboxURL; -}; - -class DeferredLoadEntity { -public: - EntityItemID entityID; - QString entityScript; - //bool forceRedownload; -}; - -struct EntityScriptContentAvailable { - EntityItemID entityID; - QString scriptOrURL; - QString contents; - bool isURL; - bool success; - QString status; -}; - -typedef std::unordered_map EntityScriptContentAvailableMap; - -typedef QList CallbackList; -typedef QHash RegisteredEventHandlers; - -class EntityScriptDetails { -public: - EntityScriptStatus status { EntityScriptStatus::PENDING }; - - // If status indicates an error, this contains a human-readable string giving more information about the error. - QString errorInfo { "" }; - - QString scriptText { "" }; - QScriptValue scriptObject { QScriptValue() }; - int64_t lastModified { 0 }; - QUrl definingSandboxURL { QUrl("about:EntityScript") }; -}; - -/**jsdoc - * The Script API provides facilities for working with scripts. - * - * @namespace Script - * - * @hifi-interface - * @hifi-client-entity - * @hifi-avatar - * @hifi-server-entity - * @hifi-assignment-client - * - * @property {string} context - The context that the script is running in: - *
    - *
  • "client": An Interface or avatar script.
  • - *
  • "entity_client": A client entity script.
  • - *
  • "entity_server": A server entity script.
  • - *
  • "agent": An assignment client script.
  • - *
- * Read-only. - * @property {string} type - The type of script that is running: - *
    - *
  • "client": An Interface script.
  • - *
  • "entity_client": A client entity script.
  • - *
  • "avatar": An avatar script.
  • - *
  • "entity_server": A server entity script.
  • - *
  • "agent": An assignment client script.
  • - *
- * Read-only. - * @property {string} filename - The filename of the script file. - * Read-only. - * @property {Script.ResourceBuckets} ExternalPaths - External resource buckets. - */ -class ScriptEngine : public BaseScriptEngine, public EntitiesScriptEngineProvider { - Q_OBJECT - Q_PROPERTY(QString context READ getContext) - Q_PROPERTY(QString type READ getTypeAsString) - Q_PROPERTY(QString fileName MEMBER _fileNameString CONSTANT) -public: - - enum Context { - CLIENT_SCRIPT, - ENTITY_CLIENT_SCRIPT, - ENTITY_SERVER_SCRIPT, - AGENT_SCRIPT + typedef ScriptValuePointer (*FunctionSignature)(ScriptContext*, ScriptEngine*); + typedef ScriptValuePointer (*MarshalFunction)(ScriptEngine*, const void*); + typedef void (*DemarshalFunction)(const ScriptValuePointer&, void*); + + enum ValueOwnership { + QtOwnership = 0, + ScriptOwnership = 1, + AutoOwnership = 2, }; - enum Type { - CLIENT, - ENTITY_CLIENT, - ENTITY_SERVER, - AGENT, - AVATAR + enum QObjectWrapOption { + ExcludeChildObjects = 0x0001, // The script object will not expose child objects as properties. + ExcludeSuperClassMethods = 0x0002, // The script object will not expose signals and slots inherited from the superclass. + ExcludeSuperClassProperties = 0x0004, // The script object will not expose properties inherited from the superclass. + ExcludeSuperClassContents = 0x0006, // Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties + ExcludeDeleteLater = 0x0010, // The script object will not expose the QObject::deleteLater() slot. + ExcludeSlots = 0x0020, // The script object will not expose the QObject's slots. + AutoCreateDynamicProperties = 0x0100, // Properties that don't already exist in the QObject will be created as dynamic properties of that object, rather than as properties of the script object. + PreferExistingWrapperObject = 0x0200, // If a wrapper object with the requested configuration already exists, return that object. + SkipMethodsInEnumeration = 0x0008, // Don't include methods (signals and slots) when enumerating the object's properties. }; - Q_ENUM(Type) - - static int processLevelMaxRetries; - ScriptEngine(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine")); - ~ScriptEngine(); - - /// run the script in a dedicated thread. This will have the side effect of evalulating - /// the current script contents and calling run(). Callers will likely want to register the script with external - /// services before calling this. - void runInThread(); - - void runDebuggable(); - - /// run the script in the callers thread, exit when stop() is called. - void run(); - - QString getFilename() const; - - QList getListOfEntityScriptIDs(); - - /**jsdoc - * Stops and unloads the current script. - *

Warning: If an assignment client script, the script gets restarted after stopping.

- * @function Script.stop - * @param {boolean} [marshal=false] - Marshal. - *

Deprecated: This parameter is deprecated and will be removed.

- * @example Stop a script after 5s. - * Script.setInterval(function () { - * print("Hello"); - * }, 1000); - * - * Script.setTimeout(function () { - * Script.stop(true); - * }, 5000); - */ - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // NOTE - this is intended to be a public interface for Agent scripts, and local scripts, but not for EntityScripts - Q_INVOKABLE void stop(bool marshal = false); - - // Stop any evaluating scripts and wait for the scripting thread to finish. - void waitTillDoneRunning(bool shutdown = false); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can - // properly ensure they are only called on the correct thread - - /**jsdoc - * @function Script.registerGlobalObject - * @param {string} name - Name. - * @param {object} object - Object. - * @deprecated This function is deprecated and will be removed. - */ - /// registers a global object by name - Q_INVOKABLE void registerGlobalObject(const QString& name, QObject* object); - - /**jsdoc - * @function Script.registerGetterSetter - * @param {string} name - Name. - * @param {function} getter - Getter. - * @param {function} setter - Setter. - * @param {string} [parent=""] - Parent. - * @deprecated This function is deprecated and will be removed. - */ - /// registers a global getter/setter - Q_INVOKABLE void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, - QScriptEngine::FunctionSignature setter, const QString& parent = QString("")); - - /**jsdoc - * @function Script.registerFunction - * @param {string} name - Name. - * @param {function} function - Function. - * @param {number} [numArguments=-1] - Number of arguments. - * @deprecated This function is deprecated and will be removed. - */ - /// register a global function - Q_INVOKABLE void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); - - /**jsdoc - * @function Script.registerFunction - * @param {string} parent - Parent. - * @param {string} name - Name. - * @param {function} function - Function. - * @param {number} [numArguments=-1] - Number of arguments. - * @deprecated This function is deprecated and will be removed. - */ - /// register a function as a method on a previously registered global object - Q_INVOKABLE void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature fun, - int numArguments = -1); - - /**jsdoc - * @function Script.registerEnum - * @param {string} name - Name. - * @param {object} enum - Enum. - * @deprecated This function is deprecated and will be removed. - */ - // WARNING: This function must be called after a registerGlobalObject that creates the namespace this enum is located in, or - // the globalObject won't function. E.g., if you have a Foo object and a Foo.FooType enum, Foo must be registered first. - /// registers a global enum - Q_INVOKABLE void registerEnum(const QString& enumName, QMetaEnum newEnum); - - /**jsdoc - * @function Script.registerValue - * @param {string} name - Name. - * @param {object} value - Value. - * @deprecated This function is deprecated and will be removed. - */ - /// registers a global object by name - Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value); - - /**jsdoc - * @function Script.evaluate - * @param {string} program - Program. - * @param {string} filename - File name. - * @param {number} [lineNumber=-1] - Line number. - * @returns {object} Object. - * @deprecated This function is deprecated and will be removed. - */ - /// evaluate some code in the context of the ScriptEngine and return the result - Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName, int lineNumber = 1); // this is also used by the script tool widget - - /**jsdoc - * @function Script.evaluateInClosure - * @param {object} locals - Locals. - * @param {object} program - Program. - * @returns {object} Object. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE QScriptValue evaluateInClosure(const QScriptValue& locals, const QScriptProgram& program); - - /// if the script engine is not already running, this will download the URL and start the process of seting it up - /// to run... NOTE - this is used by Application currently to load the url. We don't really want it to be exposed - /// to scripts. we may not need this to be invokable - void loadURL(const QUrl& scriptURL, bool reload); - bool hasValidScriptSuffix(const QString& scriptFileName); - - /**jsdoc - * Gets the context that the script is running in: Interface/avatar, client entity, server entity, or assignment client. - * @function Script.getContext - * @returns {string} The context that the script is running in: - *
    - *
  • "client": An Interface or avatar script.
  • - *
  • "entity_client": A client entity script.
  • - *
  • "entity_server": A server entity script.
  • - *
  • "agent": An assignment client script.
  • - *
- */ - Q_INVOKABLE QString getContext() const; - - /**jsdoc - * Checks whether the script is running as an Interface or avatar script. - * @function Script.isClientScript - * @returns {boolean} true if the script is running as an Interface or avatar script, false if it - * isn't. - */ - Q_INVOKABLE bool isClientScript() const { return _context == CLIENT_SCRIPT; } - - /**jsdoc - * Checks whether the application was compiled as a debug build. - * @function Script.isDebugMode - * @returns {boolean} true if the application was compiled as a debug build, false if it was - * compiled as a release build. - */ - Q_INVOKABLE bool isDebugMode() const; - - /**jsdoc - * Checks whether the script is running as a client entity script. - * @function Script.isEntityClientScript - * @returns {boolean} true if the script is running as a client entity script, false if it isn't. - */ - Q_INVOKABLE bool isEntityClientScript() const { return _context == ENTITY_CLIENT_SCRIPT; } - - /**jsdoc - * Checks whether the script is running as a server entity script. - * @function Script.isEntityServerScript - * @returns {boolean} true if the script is running as a server entity script, false if it isn't. - */ - Q_INVOKABLE bool isEntityServerScript() const { return _context == ENTITY_SERVER_SCRIPT; } - - /**jsdoc - * Checks whether the script is running as an assignment client script. - * @function Script.isAgentScript - * @returns {boolean} true if the script is running as an assignment client script, false if it - * isn't. - */ - Q_INVOKABLE bool isAgentScript() const { return _context == AGENT_SCRIPT; } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // NOTE - these are intended to be public interfaces available to scripts - - /**jsdoc - * Adds a function to the list of functions called when a particular event occurs on a particular entity. - *

See also, the {@link Entities} API.

- * @function Script.addEventHandler - * @param {Uuid} entityID - The ID of the entity. - * @param {Script.EntityEvent} eventName - The name of the event. - * @param {Script~entityEventCallback|Script~pointerEventCallback|Script~collisionEventCallback} handler - The function to - * call when the event occurs on the entity. It can be either the name of a function or an in-line definition. - * @example Report when a mouse press occurs on a particular entity. - * var entityID = Entities.addEntity({ - * type: "Box", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), - * dimensions: { x: 0.5, y: 0.5, z: 0.5 }, - * lifetime: 300 // Delete after 5 minutes. - * }); - * - * function reportMousePress(entityID, event) { - * print("Mouse pressed on entity: " + JSON.stringify(event)); - * } - * - * Script.addEventHandler(entityID, "mousePressOnEntity", reportMousePress); - */ - Q_INVOKABLE void addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler); - - /**jsdoc - * Removes a function from the list of functions called when an entity event occurs on a particular entity. - *

See also, the {@link Entities} API.

- * @function Script.removeEventHandler - * @param {Uuid} entityID - The ID of the entity. - * @param {Script.EntityEvent} eventName - The name of the entity event. - * @param {function} handler - The name of the function to no longer call when the entity event occurs on the entity. - */ - Q_INVOKABLE void removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler); - - /**jsdoc - * Starts running another script in Interface, if it isn't already running. The script is not automatically loaded next - * time Interface starts. - *

Supported Script Types: Interface Scripts • Avatar Scripts

- *

See also, {@link ScriptDiscoveryService.loadScript}.

- * @function Script.load - * @param {string} filename - The URL of the script to load. This can be relative to the current script's URL. - * @example Load a script from another script. - * // First file: scriptA.js - * print("This is script A"); - * - * // Second file: scriptB.js - * print("This is script B"); - * Script.load("scriptA.js"); - * - * // If you run scriptB.js you should see both scripts in the Running Scripts dialog. - * // And you should see the following output: - * // This is script B - * // This is script A - */ - Q_INVOKABLE void load(const QString& loadfile); - - /**jsdoc - * Includes JavaScript from other files in the current script. If a callback is specified, the files are loaded and - * included asynchronously, otherwise they are included synchronously (i.e., script execution blocks while the files are - * included). - * @function Script.include - * @variation 0 - * @param {string[]} filenames - The URLs of the scripts to include. Each can be relative to the current script. - * @param {function} [callback=null] - The function to call back when the scripts have been included. It can be either the - * name of a function or an in-line definition. - */ - Q_INVOKABLE void include(const QStringList& includeFiles, QScriptValue callback = QScriptValue()); - - /**jsdoc - * Includes JavaScript from another file in the current script. If a callback is specified, the file is loaded and included - * asynchronously, otherwise it is included synchronously (i.e., script execution blocks while the file is included). - * @function Script.include - * @param {string} filename - The URL of the script to include. It can be relative to the current script. - * @param {function} [callback=null] - The function to call back when the script has been included. It can be either the - * name of a function or an in-line definition. - * @example Include a script file asynchronously. - * // First file: scriptA.js - * print("This is script A"); - * - * // Second file: scriptB.js - * print("This is script B"); - * Script.include("scriptA.js", function () { - * print("Script A has been included"); - * }); - * - * // If you run scriptB.js you should see only scriptB.js in the running scripts list. - * // And you should see the following output: - * // This is script B - * // This is script A - * // Script A has been included - */ - Q_INVOKABLE void include(const QString& includeFile, QScriptValue callback = QScriptValue()); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // MODULE related methods - - /**jsdoc - * Provides access to methods or objects provided in an external JavaScript or JSON file. - * See {@link https://docs.vircadia.dev/script/js-tips.html} for further details. - * @function Script.require - * @param {string} module - The module to use. May be a JavaScript file, a JSON file, or the name of a system module such - * as "appUi" (i.e., the "appUi.js" system module JavaScript file). - * @returns {object|array} The value assigned to module.exports in the JavaScript file, or the value defined - * in the JSON file. - */ - Q_INVOKABLE QScriptValue require(const QString& moduleId); - - /**jsdoc - * @function Script.resetModuleCache - * @param {boolean} [deleteScriptCache=false] - Delete script cache. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void resetModuleCache(bool deleteScriptCache = false); - - QScriptValue currentModule(); - bool registerModuleWithParent(const QScriptValue& module, const QScriptValue& parent); - QScriptValue newModule(const QString& modulePath, const QScriptValue& parent = QScriptValue()); - QVariantMap fetchModuleSource(const QString& modulePath, const bool forceDownload = false); - QScriptValue instantiateModule(const QScriptValue& module, const QString& sourceCode); - - /**jsdoc - * Calls a function repeatedly, at a set interval. - * @function Script.setInterval - * @param {function} function - The function to call. This can be either the name of a function or an in-line definition. - * @param {number} interval - The interval at which to call the function, in ms. - * @returns {object} A handle to the interval timer. This can be used in {@link Script.clearInterval}. - * @example Print a message every second. - * Script.setInterval(function () { - * print("Interval timer fired"); - * }, 1000); - */ - Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS); - - /**jsdoc - * Calls a function once, after a delay. - * @function Script.setTimeout - * @param {function} function - The function to call. This can be either the name of a function or an in-line definition. - * @param {number} timeout - The delay after which to call the function, in ms. - * @returns {object} A handle to the timeout timer. This can be used in {@link Script.clearTimeout}. - * @example Print a message once, after a second. - * Script.setTimeout(function () { - * print("Timeout timer fired"); - * }, 1000); - */ - Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS); - - /**jsdoc - * Stops an interval timer set by {@link Script.setInterval|setInterval}. - * @function Script.clearInterval - * @param {object} timer - The interval timer to stop. - * @example Stop an interval timer. - * // Print a message every second. - * var timer = Script.setInterval(function () { - * print("Interval timer fired"); - * }, 1000); - * - * // Stop the timer after 10 seconds. - * Script.setTimeout(function () { - * print("Stop interval timer"); - * Script.clearInterval(timer); - * }, 10000); - */ - Q_INVOKABLE void clearInterval(QObject* timer) { stopTimer(reinterpret_cast(timer)); } - - /**jsdoc - * Stops a timeout timer set by {@link Script.setTimeout|setTimeout}. - * @function Script.clearTimeout - * @param {object} timer - The timeout timer to stop. - * @example Stop a timeout timer. - * // Print a message after two seconds. - * var timer = Script.setTimeout(function () { - * print("Timer fired"); - * }, 2000); - * - * // Uncomment the following line to stop the timer from firing. - * //Script.clearTimeout(timer); - */ - Q_INVOKABLE void clearTimeout(QObject* timer) { stopTimer(reinterpret_cast(timer)); } - - /**jsdoc - * Prints a message to the program log and emits {@link Script.printedMessage}. - *

Alternatively, you can use {@link print} or one of the {@link console} API methods.

- * @function Script.print - * @param {string} message - The message to print. - */ - Q_INVOKABLE void print(const QString& message); - - /**jsdoc - * Resolves a relative path to an absolute path. The relative path is relative to the script's location. - * @function Script.resolvePath - * @param {string} path - The relative path to resolve. - * @returns {string} The absolute path. - * @example Report the directory and filename of the running script. - * print(Script.resolvePath("")); - * @example Report the directory of the running script. - * print(Script.resolvePath(".")); - * @example Report the path to a file located relative to the running script. - * print(Script.resolvePath("../assets/sounds/hello.wav")); - */ - Q_INVOKABLE QUrl resolvePath(const QString& path) const; - - /**jsdoc - * Gets the path to the resources directory for QML files. - * @function Script.resourcesPath - * @returns {string} The path to the resources directory for QML files. - */ - Q_INVOKABLE QUrl resourcesPath() const; - - /**jsdoc - * Starts timing a section of code in order to send usage data about it to Vircadia. Shouldn't be used outside of the - * standard scripts. - * @function Script.beginProfileRange - * @param {string} label - A name that identifies the section of code. - */ - Q_INVOKABLE void beginProfileRange(const QString& label) const; + Q_DECLARE_FLAGS(QObjectWrapOptions, QObjectWrapOption); - /**jsdoc - * Finishes timing a section of code in order to send usage data about it to Vircadia. Shouldn't be used outside of - * the standard scripts. - * @function Script.endProfileRange - * @param {string} label - A name that identifies the section of code. - */ - Q_INVOKABLE void endProfileRange(const QString& label) const; +public: + virtual void abortEvaluation() = 0; + virtual void clearExceptions() = 0; + virtual ScriptValuePointer cloneUncaughtException(const QString& detail = QString()) = 0; + virtual ScriptContext* currentContext() const = 0; + virtual ScriptValuePointer evaluate(const QString& program, const QString& fileName = QString()) = 0; + virtual ScriptValuePointer evaluate(const ScriptProgramPointer &program) = 0; + virtual ScriptValuePointer evaluateInClosure(const ScriptValuePointer& locals, const ScriptProgramPointer& program) = 0; + virtual ScriptValuePointer globalObject() const = 0; + virtual bool hasUncaughtException() const = 0; + virtual bool isEvaluating() const = 0; + virtual ScriptValuePointer lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1) = 0; + virtual ScriptValuePointer makeError(const ScriptValuePointer& other = ScriptValuePointer(), const QString& type = "Error") = 0; + virtual ScriptManager* manager() const = 0; + virtual bool maybeEmitUncaughtException(const QString& debugHint = QString()) = 0; + virtual ScriptValuePointer newArray(uint length = 0) = 0; + virtual ScriptValuePointer newArrayBuffer(const QByteArray& message) = 0; + virtual ScriptValuePointer newFunction(FunctionSignature fun, int length = 0) = 0; + virtual ScriptValuePointer newObject() = 0; + virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName) = 0; + virtual ScriptValuePointer newQObject(QObject *object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions &options = QObjectWrapOptions()) = 0; + virtual ScriptValuePointer newValue(bool value) = 0; + virtual ScriptValuePointer newValue(int value) = 0; + virtual ScriptValuePointer newValue(uint value) = 0; + virtual ScriptValuePointer newValue(double value) = 0; + virtual ScriptValuePointer newValue(const QString& value) = 0; + virtual ScriptValuePointer newValue(const QLatin1String& value) = 0; + virtual ScriptValuePointer newValue(const char* value) = 0; + virtual ScriptValuePointer newVariant(const QVariant& value) = 0; + virtual ScriptValuePointer nullValue() = 0; + virtual bool raiseException(const ScriptValuePointer& exception) = 0; + virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) = 0; + virtual void registerFunction(const QString& name, FunctionSignature fun, int numArguments = -1) = 0; + virtual void registerFunction(const QString& parent, const QString& name, FunctionSignature fun, int numArguments = -1) = 0; + virtual void registerGetterSetter(const QString& name, FunctionSignature getter, FunctionSignature setter, const QString& parent = QString("")) = 0; + virtual void registerGlobalObject(const QString& name, QObject* object) = 0; + virtual void setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype) = 0; + virtual void setObjectName(const QString& name) = 0; + virtual bool setProperty(const char* name, const QVariant& value) = 0; + virtual void setProcessEventsInterval(int interval) = 0; + virtual QThread* thread() const = 0; + virtual ScriptValuePointer undefinedValue() = 0; + virtual ScriptValuePointer uncaughtException() const = 0; + virtual QStringList uncaughtExceptionBacktrace() const = 0; + virtual int uncaughtExceptionLineNumber() const = 0; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Entity Script Related methods +public: + // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways + bool IS_THREADSAFE_INVOCATION(const QString& method); - /**jsdoc - * Checks whether an entity has an entity script running. - * @function Script.isEntityScriptRunning - * @param {Uuid} entityID - The ID of the entity. - * @returns {boolean} true if the entity has an entity script running, false if it doesn't. - */ - Q_INVOKABLE bool isEntityScriptRunning(const EntityItemID& entityID) { - QReadLocker locker { &_entityScriptsLock }; - auto it = _entityScripts.constFind(entityID); - return it != _entityScripts.constEnd() && it->status == EntityScriptStatus::RUNNING; +public: + template + inline T fromScriptValue(const ScriptValuePointer& value) { + return scriptvalue_cast(value); } - QVariant cloneEntityScriptDetails(const EntityItemID& entityID); - QFuture getLocalEntityScriptDetails(const EntityItemID& entityID) override; - - /**jsdoc - * @function Script.loadEntityScript - * @param {Uuid} entityID - Entity ID. - * @param {string} script - Script. - * @param {boolean} forceRedownload - Force re-download. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload); - - /**jsdoc - * @function Script.unloadEntityScript - * @param {Uuid} entityID - Entity ID. - * @param {boolean} [shouldRemoveFromMap=false] - Should remove from map. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap = false); // will call unload method - - /**jsdoc - * @function Script.unloadAllEntityScripts - * @param {boolean} [blockingCall=false] - Wait for completion if call moved to another thread. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void unloadAllEntityScripts(bool blockingCall = false); - - /**jsdoc - * Calls a method in an entity script. - * @function Script.callEntityScriptMethod - * @param {Uuid} entityID - The ID of the entity running the entity script. - * @param {string} methodName - The name of the method to call. - * @param {string[]} [parameters=[]] - The parameters to call the specified method with. - * @param {Uuid} [remoteCallerID=Uuid.NULL] - An ID that identifies the caller. - */ - Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, - const QStringList& params = QStringList(), - const QUuid& remoteCallerID = QUuid()) override; - - /**jsdoc - * Calls a method in an entity script. - * @function Script.callEntityScriptMethod - * @param {Uuid} entityID - Entity ID. - * @param {string} methodName - Method name. - * @param {PointerEvent} event - Pointer event. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event); - - /**jsdoc - * Calls a method in an entity script. - * @function Script.callEntityScriptMethod - * @param {Uuid} entityID - Entity ID. - * @param {string} methodName - Method name. - * @param {Uuid} otherID - Other entity ID. - * @param {Collision} collision - Collision. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision); - - /**jsdoc - * Manually runs the JavaScript garbage collector which reclaims memory by disposing of objects that are no longer - * reachable. - * @function Script.requestGarbageCollection - */ - Q_INVOKABLE void requestGarbageCollection() { collectGarbage(); } - - /**jsdoc - * @function Script.generateUUID - * @returns {Uuid} A new UUID. - * @deprecated This function is deprecated and will be removed. Use {@link Uuid(0).generate|Uuid.generate} instead. - */ - Q_INVOKABLE QUuid generateUUID() { return QUuid::createUuid(); } - - void setType(Type type) { _type = type; }; - Type getType() { return _type; }; - QString getTypeAsString() const; - - bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget - bool isRunning() const { return _isRunning; } // used by ScriptWidget - - // this is used by code in ScriptEngines.cpp during the "reload all" operation - bool isStopping() const { return _isStopping; } - - bool isDebuggable() const { return _debuggable; } - - void disconnectNonEssentialSignals(); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // These are currently used by Application to track if a script is user loaded or not. Consider finding a solution - // inside of Application so that the ScriptEngine class is not polluted by this notion - void setUserLoaded(bool isUserLoaded) { _isUserLoaded = isUserLoaded; } - bool isUserLoaded() const { return _isUserLoaded; } - - void setQuitWhenFinished(const bool quitWhenFinished) { _quitWhenFinished = quitWhenFinished; } - bool isQuitWhenFinished() const { return _quitWhenFinished; } - - // NOTE - this is used by the TypedArray implementation. we need to review this for thread safety - ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - - void setEmitScriptUpdatesFunction(std::function func) { _emitScriptUpdates = func; } - - void scriptErrorMessage(const QString& message); - void scriptWarningMessage(const QString& message); - void scriptInfoMessage(const QString& message); - void scriptPrintedMessage(const QString& message); - void clearDebugLogWindow(); - int getNumRunningEntityScripts() const; - bool getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const; - bool hasEntityScriptDetails(const EntityItemID& entityID) const; - - void setScriptEngines(QSharedPointer& scriptEngines) { _scriptEngines = scriptEngines; } - - /**jsdoc - * Gets the URL for an asset in an external resource bucket. (The location where the bucket is hosted may change over time - * but this method will return the asset's current URL.) - * @function Script.getExternalPath - * @param {Script.ResourceBucket} bucket - The external resource bucket that the asset is in. - * @param {string} path - The path within the external resource bucket where the asset is located. - *

Normally, this should start with a path or filename to be appended to the bucket URL. - * Alternatively, it can be a relative path starting with ./ or ../, to navigate within the - * resource bucket's URL.

- * @Returns {string} The URL of an external asset. - * @example Report the URL of a default particle. - * print(Script.getExternalPath(Script.ExternalPaths.Assets, "Bazaar/Assets/Textures/Defaults/Interface/default_particle.png")); - * @example Report the root directory where the Vircadia assets are located. - * print(Script.getExternalPath(Script.ExternalPaths.Assets, ".")); - */ - Q_INVOKABLE QString getExternalPath(ExternalResource::Bucket bucket, const QString& path); - -public slots: - - /**jsdoc - * @function Script.callAnimationStateHandler - * @param {function} callback - Callback function. - * @param {object} parameters - Parameters. - * @param {string[]} names - Names. - * @param {boolean} useNames - Use names. - * @param {function} resultHandler - Result handler. - * @deprecated This function is deprecated and will be removed. - */ - void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); - - /**jsdoc - * @function Script.updateMemoryCost - * @param {number} deltaSize - Delta size. - * @deprecated This function is deprecated and will be removed. - */ - void updateMemoryCost(const qint64&); - -signals: - - /**jsdoc - * @function Script.scriptLoaded - * @param {string} filename - File name. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void scriptLoaded(const QString& scriptFilename); - - /**jsdoc - * @function Script.errorLoadingScript - * @param {string} filename - File name. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void errorLoadingScript(const QString& scriptFilename); - - /**jsdoc - * Triggered frequently at a system-determined interval. - * @function Script.update - * @param {number} deltaTime - The time since the last update, in s. - * @returns {Signal} - * @example Report script update intervals. - * Script.update.connect(function (deltaTime) { - * print("Update: " + deltaTime); - * }); - */ - void update(float deltaTime); - - /**jsdoc - * Triggered when the script is stopping. - * @function Script.scriptEnding - * @returns {Signal} - * @example Report when a script is stopping. - * print("Script started"); - * - * Script.scriptEnding.connect(function () { - * print("Script ending"); - * }); - * - * Script.setTimeout(function () { - * print("Stopping script"); - * Script.stop(); - * }, 1000); - */ - void scriptEnding(); - - /**jsdoc - * @function Script.finished - * @param {string} filename - File name. - * @param {object} engine - Engine. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void finished(const QString& fileNameString, ScriptEnginePointer); - - /**jsdoc - * @function Script.cleanupMenuItem - * @param {string} menuItem - Menu item. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void cleanupMenuItem(const QString& menuItemString); - /**jsdoc - * Triggered when the script prints a message to the program log via {@link print}, {@link Script.print}, - * {@link console.log}, {@link console.debug}, {@link console.group}, {@link console.groupEnd}, {@link console.time}, or - * {@link console.timeEnd}. - * @function Script.printedMessage - * @param {string} message - The message. - * @param {string} scriptName - The name of the script that generated the message. - * @returns {Signal} - */ - void printedMessage(const QString& message, const QString& scriptName); - - /**jsdoc - * Triggered when the script generates an error, {@link console.error} or {@link console.exception} is called, or - * {@link console.assert} is called and fails. - * @function Script.errorMessage - * @param {string} message - The error message. - * @param {string} scriptName - The name of the script that generated the error message. - * @returns {Signal} - */ - void errorMessage(const QString& message, const QString& scriptName); - - /**jsdoc - * Triggered when the script generates a warning or {@link console.warn} is called. - * @function Script.warningMessage - * @param {string} message - The warning message. - * @param {string} scriptName - The name of the script that generated the warning message. - * @returns {Signal} - */ - void warningMessage(const QString& message, const QString& scriptName); - - /**jsdoc - * Triggered when the script generates an information message or {@link console.info} is called. - * @function Script.infoMessage - * @param {string} message - The information message. - * @param {string} scriptName - The name of the script that generated the information message. - * @returns {Signal} - */ - void infoMessage(const QString& message, const QString& scriptName); - - /**jsdoc - * Triggered when the running state of the script changes, e.g., from running to stopping. - * @function Script.runningStateChanged - * @returns {Signal} - */ - void runningStateChanged(); - - /**jsdoc - * @function Script.clearDebugWindow - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void clearDebugWindow(); - - /**jsdoc - * @function Script.loadScript - * @param {string} scriptName - Script name. - * @param {boolean} isUserLoaded - Is user loaded. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void loadScript(const QString& scriptName, bool isUserLoaded); - - /**jsdoc - * @function Script.reloadScript - * @param {string} scriptName - Script name. - * @param {boolean} isUserLoaded - Is user loaded. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void reloadScript(const QString& scriptName, bool isUserLoaded); - - /**jsdoc - * Triggered when the script has stopped. - * @function Script.doneRunning - * @returns {Signal} - */ - void doneRunning(); - - /**jsdoc - * @function Script.entityScriptDetailsUpdated - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - // Emitted when an entity script is added or removed, or when the status of an entity - // script is updated (goes from RUNNING to ERROR_RUNNING_SCRIPT, for example) - void entityScriptDetailsUpdated(); - - /**jsdoc - * Triggered when the script starts for the user. See also, {@link Entities.preload}. - *

Supported Script Types: Client Entity Scripts • Server Entity Scripts

- * @function Script.entityScriptPreloadFinished - * @param {Uuid} entityID - The ID of the entity that the script is running in. - * @returns {Signal} - * @example Get the ID of the entity that a client entity script is running in. - * var entityScript = function () { - * this.entityID = Uuid.NULL; - * }; - * - * Script.entityScriptPreloadFinished.connect(function (entityID) { - * this.entityID = entityID; - * print("Entity ID: " + this.entityID); - * }); - * - * var entityID = Entities.addEntity({ - * type: "Box", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), - * dimensions: { x: 0.5, y: 0.5, z: 0.5 }, - * color: { red: 255, green: 0, blue: 0 }, - * script: "(" + entityScript + ")", // Could host the script on a Web server instead. - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - // Emitted when an entity script has finished running preload - void entityScriptPreloadFinished(const EntityItemID& entityID); - -protected: - void init(); - - /**jsdoc - * @function Script.executeOnScriptThread - * @param {function} function - Function. - * @param {ConnectionType} [type=2] - Connection type. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void executeOnScriptThread(std::function function, const Qt::ConnectionType& type = Qt::QueuedConnection ); - - /**jsdoc - * @function Script._requireResolve - * @param {string} module - Module. - * @param {string} [relativeTo=""] - Relative to. - * @returns {string} Result. - * @deprecated This function is deprecated and will be removed. - */ - // note: this is not meant to be called directly, but just to have QMetaObject take care of wiring it up in general; - // then inside of init() we just have to do "Script.require.resolve = Script._requireResolve;" - Q_INVOKABLE QString _requireResolve(const QString& moduleId, const QString& relativeTo = QString()); - - QString logException(const QScriptValue& exception); - void timerFired(); - void stopAllTimers(); - void stopAllTimersForEntityScript(const EntityItemID& entityID); - void refreshFileScript(const EntityItemID& entityID); - void updateEntityScriptStatus(const EntityItemID& entityID, const EntityScriptStatus& status, const QString& errorInfo = QString()); - void setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details); - void setParentURL(const QString& parentURL) { _parentURL = parentURL; } - - QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); - void stopTimer(QTimer* timer); - - QHash _registeredHandlers; - void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs); - - /**jsdoc - * @function Script.entityScriptContentAvailable - * @param {Uuid} entityID - Entity ID. - * @param {string} scriptOrURL - Path. - * @param {string} contents - Contents. - * @param {boolean} isURL - Is a URL. - * @param {boolean} success - Success. - * @param {string} status - Status. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success, const QString& status); - - EntityItemID currentEntityIdentifier; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution. - QUrl currentSandboxURL; // The toplevel url string for the entity script that loaded the code being executed, else empty. - void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation); - void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args); - - Context _context; - Type _type; - QString _scriptContents; - QString _parentURL; - std::atomic _isFinished { false }; - std::atomic _isRunning { false }; - std::atomic _isStopping { false }; - bool _isInitialized { false }; - QHash _timerFunctionMap; - QSet _includedURLs; - mutable QReadWriteLock _entityScriptsLock { QReadWriteLock::Recursive }; - QHash _entityScripts; - EntityScriptContentAvailableMap _contentAvailableQueue; - - bool _isThreaded { false }; - QScriptEngineDebugger* _debugger { nullptr }; - bool _debuggable { false }; - qint64 _lastUpdate; - - QString _fileNameString; - Quat _quatLibrary; - Vec3 _vec3Library; - Mat4 _mat4Library; - ScriptUUID _uuidLibrary; - ConsoleScriptingInterface _consoleScriptingInterface; - std::atomic _isUserLoaded { false }; - bool _isReloading { false }; - - std::atomic _quitWhenFinished; - - ArrayBufferClass* _arrayBufferClass; - - AssetScriptingInterface* _assetScriptingInterface; - - std::function _emitScriptUpdates{ []() { return true; } }; - - std::recursive_mutex _lock; - - std::chrono::microseconds _totalTimerExecution { 0 }; - - static const QString _SETTINGS_ENABLE_EXTENDED_MODULE_COMPAT; - static const QString _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS; - - Setting::Handle _enableExtendedJSExceptions { _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS, true }; + template + inline ScriptValuePointer toScriptValue(const T& value) { + return scriptValueFromValue(this, value); + } - QWeakPointer _scriptEngines; +public: // not for public use, but I don't like how Qt strings this along with private friend functions + virtual ScriptValuePointer create(int type, const void* ptr) = 0; + virtual bool convert(const ScriptValuePointer& value, int type, void* ptr) = 0; + virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df, const ScriptValuePointer& prototype) = 0; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptEngine::QObjectWrapOptions) + +ScriptEnginePointer newScriptEngine(ScriptManager* manager = nullptr); -ScriptEnginePointer scriptEngineFactory(ScriptEngine::Context context, - const QString& scriptContents, - const QString& fileNameString); +// Standardized CPS callback helpers (see: http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/) +// These two helpers allow async JS APIs that use a callback parameter to be more friendly to scripters by accepting thisObject +// context and adopting a consistent and intuitable callback signature: +// function callback(err, result) { if (err) { ... } else { /* do stuff with result */ } } +// +// To use, first pass the user-specified callback args in the same order used with optionally-scoped Qt signal connections: +// auto handler = makeScopedHandlerObject(scopeOrCallback, optionalMethodOrName); +// And then invoke the scoped handler later per CPS conventions: +// auto result = callScopedHandlerObject(handler, err, result); +ScriptValuePointer makeScopedHandlerObject(ScriptValuePointer scopeOrCallback, ScriptValuePointer methodOrName); +ScriptValuePointer callScopedHandlerObject(ScriptValuePointer handler, ScriptValuePointer err, ScriptValuePointer result); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Inline implementations +/* +QThread* ScriptEngine::thread() const { + QObject* qobject = toQObject(); + if (qobject == nullptr) { + return nullptr; + } + return qobject->thread(); +} +*/ -#endif // hifi_ScriptEngine_h +#endif // hifi_ScriptEngine_h diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h new file mode 100644 index 00000000000..ba56f920d4b --- /dev/null +++ b/libraries/script-engine/src/ScriptEngineCast.h @@ -0,0 +1,99 @@ +// +// ScriptEngineCast.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/9/2021. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptEngineCast_h +#define hifi_ScriptEngineCast_h + +// Object conversion helpers (copied from QScriptEngine) + +#include "ScriptEngine.h" +#include "ScriptValue.h" + +template +inline ScriptValuePointer scriptValueFromValue(ScriptEngine* engine, const T& t) { + if (!engine) { + return ScriptValuePointer(); + } + + return engine->create(qMetaTypeId(), &t); +} + +template <> +inline ScriptValuePointer scriptValueFromValue(ScriptEngine* engine, const QVariant& v) { + if (!engine) { + return ScriptValuePointer(); + } + + return engine->create(v.userType(), v.data()); +} + +template +T scriptvalue_cast(const ScriptValuePointer& value) { + T t; + const int id = qMetaTypeId(); + + auto engine = value->engine(); + if (engine && engine->convert(value, id, &t)) { + return t; + } else if (value->isVariant()) { + return qvariant_cast(value->toVariant()); + } + + return T(); +} + +template <> +inline QVariant scriptvalue_cast(const ScriptValuePointer& value) { + return value->toVariant(); +} + +template +int scriptRegisterMetaType(ScriptEngine* eng, + ScriptValuePointer (*toScriptValue)(ScriptEngine*, const T& t), + void (*fromScriptValue)(const ScriptValuePointer&, T& t), + const ScriptValuePointer& prototype = ScriptValuePointer(), + T* = 0) { + const int id = qRegisterMetaType(); // make sure it's registered + eng->registerCustomType(id, reinterpret_cast(toScriptValue), + reinterpret_cast(fromScriptValue), prototype); + return id; +} + +template +ScriptValuePointer scriptValueFromSequence(ScriptEngine* eng, const Container& cont) { + ScriptValuePointer a = eng->newArray(); + typename Container::const_iterator begin = cont.begin(); + typename Container::const_iterator end = cont.end(); + typename Container::const_iterator it; + quint32 i; + for (it = begin, i = 0; it != end; ++it, ++i) { + a->setProperty(i, eng->toScriptValue(*it)); + } + return a; +} + +template +void scriptValueToSequence(const ScriptValuePointer& value, Container& cont) { + quint32 len = value->property(QLatin1String("length"))->toUInt32(); + for (quint32 i = 0; i < len; ++i) { + ScriptValuePointer item = value->property(i); + cont.push_back(scriptvalue_cast(item)); + } +} + +template +int scriptRegisterSequenceMetaType(ScriptEngine* engine, + const ScriptValuePointer& prototype = ScriptValuePointer(), + T* = 0) { + return scriptRegisterMetaType(engine, scriptValueFromSequence, scriptValueToSequence, prototype); +} + +#endif // hifi_ScriptEngineCast_h diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index d091e6e4b52..3ccdbaaf546 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -18,6 +19,7 @@ #include #include +#include "ScriptCache.h" #include "ScriptEngine.h" #include "ScriptEngineLogging.h" @@ -65,7 +67,7 @@ void ScriptEngines::onErrorLoadingScript(const QString& url) { emit errorLoadingScript(url); } -ScriptEngines::ScriptEngines(ScriptEngine::Context context, const QUrl& defaultScriptsOverride) +ScriptEngines::ScriptEngines(ScriptManager::Context context, const QUrl& defaultScriptsOverride) : _context(context), _defaultScriptsOverride(defaultScriptsOverride) { scriptGatekeeper.initialize(); @@ -138,53 +140,53 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) { QObject* scriptsModel(); -void ScriptEngines::addScriptEngine(ScriptEnginePointer engine) { +void ScriptEngines::addScriptEngine(ScriptManagerPointer manager) { if (!_isStopped) { QMutexLocker locker(&_allScriptsMutex); - _allKnownScriptEngines.insert(engine); + _allKnownScriptManagers.insert(manager); } } -void ScriptEngines::removeScriptEngine(ScriptEnginePointer engine) { +void ScriptEngines::removeScriptEngine(ScriptManagerPointer manager) { // If we're not already in the middle of stopping all scripts, then we should remove ourselves // from the list of running scripts. We don't do this if we're in the process of stopping all scripts // because that method removes scripts from its list as it iterates them if (!_isStopped) { QMutexLocker locker(&_allScriptsMutex); - _allKnownScriptEngines.remove(engine); + _allKnownScriptManagers.remove(manager); } } void ScriptEngines::shutdownScripting() { _isStopped = true; QMutexLocker locker(&_allScriptsMutex); - qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size(); + qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptManagers.size(); - QMutableSetIterator i(_allKnownScriptEngines); + QMutableSetIterator i(_allKnownScriptManagers); while (i.hasNext()) { - ScriptEnginePointer scriptEngine = i.next(); - QString scriptName = scriptEngine->getFilename(); + ScriptManagerPointer scriptManager = i.next(); + QString scriptName = scriptManager->getFilename(); // NOTE: typically all script engines are running. But there's at least one known exception to this, the // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using // them. We don't need to stop scripts that aren't running. // TODO: Scripts could be shut down faster if we spread them across a threadpool. - if (scriptEngine->isRunning()) { + if (scriptManager->isRunning()) { qCDebug(scriptengine) << "about to shutdown script:" << scriptName; // We disconnect any script engine signals from the application because we don't want to do any // extra stopScript/loadScript processing that the Application normally does when scripts start // and stop. We can safely short circuit this because we know we're in the "quitting" process - scriptEngine->disconnect(this); + scriptManager->disconnect(this); // Gracefully stop the engine's scripting thread - scriptEngine->stop(); + scriptManager->stop(); // We need to wait for the engine to be done running before we proceed, because we don't // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing // any application state after we leave this stopAllScripts() method qCDebug(scriptengine) << "waiting on script:" << scriptName; - scriptEngine->waitTillDoneRunning(true); + scriptManager->waitTillDoneRunning(true); qCDebug(scriptengine) << "done waiting on script:" << scriptName; } // Once the script is stopped, we can remove it from our set @@ -372,8 +374,8 @@ void ScriptEngines::saveScripts() { QVariantList list; { - QReadLocker lock(&_scriptEnginesHashLock); - for (auto it = _scriptEnginesHash.begin(); it != _scriptEnginesHash.end(); ++it) { + QReadLocker lock(&_scriptManagersHashLock); + for (auto it = _scriptManagersHash.begin(); it != _scriptManagersHash.end(); ++it) { // Save user-loaded scripts, only if they are set to quit when finished if (it.value() && it.value()->isUserLoaded() && !it.value()->isQuitWhenFinished()) { auto normalizedUrl = normalizeScriptURL(it.key()); @@ -390,8 +392,8 @@ void ScriptEngines::saveScripts() { } QStringList ScriptEngines::getRunningScripts() { - QReadLocker lock(&_scriptEnginesHashLock); - QList urls = _scriptEnginesHash.keys(); + QReadLocker lock(&_scriptManagersHashLock); + QList urls = _scriptManagersHash.keys(); QStringList result; for (auto url : urls) { result.append(url.toString()); @@ -400,33 +402,33 @@ QStringList ScriptEngines::getRunningScripts() { } void ScriptEngines::stopAllScripts(bool restart) { - QReadLocker lock(&_scriptEnginesHashLock); + QReadLocker lock(&_scriptManagersHashLock); if (_isReloading) { return; } - for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); - it != _scriptEnginesHash.constEnd(); it++) { - ScriptEnginePointer scriptEngine = it.value(); + for (QHash::const_iterator it = _scriptManagersHash.constBegin(); + it != _scriptManagersHash.constEnd(); it++) { + ScriptManagerPointer scriptManager = it.value(); // skip already stopped scripts - if (scriptEngine->isFinished() || scriptEngine->isStopping()) { + if (scriptManager->isFinished() || scriptManager->isStopping()) { continue; } bool isOverrideScript = it.key().toString().compare(this->_defaultScriptsOverride.toString()) == 0; // queue user scripts if restarting - if (restart && (scriptEngine->isUserLoaded() || isOverrideScript)) { + if (restart && (scriptManager->isUserLoaded() || isOverrideScript)) { _isReloading = true; - ScriptEngine::Type type = scriptEngine->getType(); + ScriptManager::Type type = scriptManager->getType(); - connect(scriptEngine.data(), &ScriptEngine::finished, this, [this, type, isOverrideScript] (QString scriptName) { + connect(scriptManager.data(), &ScriptManager::finished, this, [this, type, isOverrideScript](QString scriptName) { reloadScript(scriptName, !isOverrideScript)->setType(type); }); } // stop all scripts - scriptEngine->stop(); + scriptManager->stop(); } if (restart) { @@ -446,23 +448,23 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { scriptURL = normalizeScriptURL(QUrl::fromLocalFile(rawScriptURL)); } - QReadLocker lock(&_scriptEnginesHashLock); - if (_scriptEnginesHash.contains(scriptURL)) { - ScriptEnginePointer scriptEngine = _scriptEnginesHash[scriptURL]; + QReadLocker lock(&_scriptManagersHashLock); + if (_scriptManagersHash.contains(scriptURL)) { + ScriptManagerPointer scriptManager = _scriptManagersHash[scriptURL]; if (restart) { - bool isUserLoaded = scriptEngine->isUserLoaded(); - ScriptEngine::Type type = scriptEngine->getType(); + bool isUserLoaded = scriptManager->isUserLoaded(); + ScriptManager::Type type = scriptManager->getType(); auto scriptCache = DependencyManager::get(); scriptCache->deleteScript(scriptURL); - if (!scriptEngine->isStopping()) { - connect(scriptEngine.data(), &ScriptEngine::finished, - this, [this, isUserLoaded, type](QString scriptName, ScriptEnginePointer engine) { + if (!scriptManager->isStopping()) { + connect(scriptManager.data(), &ScriptManager::finished, + this, [this, isUserLoaded, type](QString scriptName, ScriptManagerPointer manager) { reloadScript(scriptName, isUserLoaded)->setType(type); }); } } - scriptEngine->stop(); + scriptManager->stop(); stoppedScript = true; } } @@ -480,11 +482,11 @@ void ScriptEngines::reloadAllScripts() { stopAllScripts(true); } -ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, +ScriptManagerPointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, bool activateMainWindow, bool reload, bool quitWhenFinished) { if (thread() != QThread::currentThread()) { - ScriptEnginePointer result { nullptr }; - BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEnginePointer, result), + ScriptManagerPointer result { nullptr }; + BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptManagerPointer, result), Q_ARG(QUrl, scriptFilename), Q_ARG(bool, isUserLoaded), Q_ARG(bool, loadScriptFromEditor), @@ -508,41 +510,41 @@ ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool i scriptUrl = QUrl(FileUtils::selectFile(scriptUrl.toString())); - auto scriptEngine = getScriptEngine(scriptUrl); - if (scriptEngine && !scriptEngine->isStopping()) { - return scriptEngine; + auto scriptManager = getScriptEngine(scriptUrl); + if (scriptManager && !scriptManager->isStopping()) { + return scriptManager; } - scriptEngine = scriptEngineFactory(_context, NO_SCRIPT, "about:" + scriptFilename.fileName()); - scriptEngine->setUserLoaded(isUserLoaded); - scriptEngine->setQuitWhenFinished(quitWhenFinished); + scriptManager = scriptManagerFactory(_context, NO_SCRIPT, "about:" + scriptFilename.fileName()); + scriptManager->setUserLoaded(isUserLoaded); + scriptManager->setQuitWhenFinished(quitWhenFinished); if (scriptFilename.isEmpty() || !scriptUrl.isValid()) { - launchScriptEngine(scriptEngine); + launchScriptEngine(scriptManager); } else { // connect to the appropriate signals of this script engine - connect(scriptEngine.data(), &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded); - connect(scriptEngine.data(), &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); + connect(scriptManager.data(), &ScriptManager::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded); + connect(scriptManager.data(), &ScriptManager::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); // Shutdown Interface when script finishes, if requested if (quitWhenFinished) { - connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::quitWhenFinished); + connect(scriptManager.data(), &ScriptManager::finished, this, &ScriptEngines::quitWhenFinished); } // get the script engine object to load the script at the designated script URL - scriptEngine->loadURL(scriptUrl, reload); + scriptManager->loadURL(scriptUrl, reload); } - return scriptEngine; + return scriptManager; } -ScriptEnginePointer ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { - ScriptEnginePointer result; +ScriptManagerPointer ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { + ScriptManagerPointer result; { - QReadLocker lock(&_scriptEnginesHashLock); + QReadLocker lock(&_scriptManagersHashLock); const QUrl scriptURL = normalizeScriptURL(rawScriptURL); - auto it = _scriptEnginesHash.find(scriptURL); - if (it != _scriptEnginesHash.end()) { + auto it = _scriptManagersHash.find(scriptURL); + if (it != _scriptManagersHash.end()) { result = it.value(); } } @@ -552,16 +554,15 @@ ScriptEnginePointer ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { // FIXME - change to new version of ScriptCache loading notification void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { UserActivityLogger::getInstance().loadedScript(rawScriptURL); - QSharedPointer baseScriptEngine = qobject_cast(sender())->sharedFromThis(); - ScriptEnginePointer scriptEngine = qSharedPointerCast(baseScriptEngine); + ScriptManagerPointer scriptEngine = qobject_cast(sender())->sharedFromThis(); launchScriptEngine(scriptEngine); { - QWriteLocker lock(&_scriptEnginesHashLock); + QWriteLocker lock(&_scriptManagersHashLock); QUrl url = QUrl(rawScriptURL); QUrl normalized = normalizeScriptURL(url); - _scriptEnginesHash.insertMulti(normalized, scriptEngine); + _scriptManagersHash.insertMulti(normalized, scriptEngine); } // Update settings with new script @@ -573,50 +574,50 @@ void ScriptEngines::quitWhenFinished() { qApp->quit(); } -int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) { - auto nativeCount = DependencyManager::get()->runScriptInitializers(scriptEngine.data()); - return nativeCount + ScriptInitializerMixin::runScriptInitializers(scriptEngine); +int ScriptEngines::runScriptInitializers(ScriptManagerPointer scriptManager) { + auto nativeCount = DependencyManager::get()->runScriptInitializers(scriptManager->engine().data()); + return nativeCount + ScriptInitializerMixin::runScriptInitializers(scriptManager); } -void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) { - connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection); - connect(scriptEngine.data(), &ScriptEngine::loadScript, [this](const QString& scriptName, bool userLoaded) { +void ScriptEngines::launchScriptEngine(ScriptManagerPointer scriptManager) { + connect(scriptManager.data(), &ScriptManager::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection); + connect(scriptManager.data(), &ScriptManager::loadScript, [this](const QString& scriptName, bool userLoaded) { loadScript(scriptName, userLoaded); }); - connect(scriptEngine.data(), &ScriptEngine::reloadScript, [this](const QString& scriptName, bool userLoaded) { + connect(scriptManager.data(), &ScriptManager::reloadScript, [this](const QString& scriptName, bool userLoaded) { loadScript(scriptName, userLoaded, false, false, true); }); // register our application services and set it off on its own thread - runScriptInitializers(scriptEngine); + runScriptInitializers(scriptManager); // FIXME disabling 'shift key' debugging for now. If you start up the application with // the shift key held down, it triggers a deadlock because of script interfaces running // on the main thread - auto const wantDebug = scriptEngine->isDebuggable(); // || (qApp->queryKeyboardModifiers() & Qt::ShiftModifier); + auto const wantDebug = scriptManager->isDebuggable(); // || (qApp->queryKeyboardModifiers() & Qt::ShiftModifier); if (HIFI_SCRIPT_DEBUGGABLES && wantDebug) { - scriptEngine->runDebuggable(); + scriptManager->runDebuggable(); } else { - scriptEngine->runInThread(); + scriptManager->runInThread(); } } -void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEnginePointer engine) { +void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptManagerPointer manager) { bool removed = false; { - QWriteLocker lock(&_scriptEnginesHashLock); + QWriteLocker lock(&_scriptManagersHashLock); const QUrl scriptURL = normalizeScriptURL(QUrl(rawScriptURL)); - for (auto it = _scriptEnginesHash.find(scriptURL); it != _scriptEnginesHash.end(); ++it) { - if (it.value() == engine) { - _scriptEnginesHash.erase(it); + for (auto it = _scriptManagersHash.find(scriptURL); it != _scriptManagersHash.end(); ++it) { + if (it.value() == manager) { + _scriptManagersHash.erase(it); removed = true; break; } } } - removeScriptEngine(engine); + removeScriptEngine(manager); if (removed && !_isReloading) { // Update settings with removed script diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 8c897f70fd6..eca37cd3580 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -16,18 +16,18 @@ #include #include #include +#include +#include #include #include #include +#include "ScriptManager.h" -#include "ScriptEngine.h" #include "ScriptsModel.h" #include "ScriptsModelFilter.h" #include "ScriptGatekeeper.h" -class ScriptEngine; - /**jsdoc * The ScriptDiscoveryService API provides facilities to work with Interface scripts. * @@ -50,7 +50,7 @@ class ScriptEngine; * Read-only. */ -class ScriptEngines : public QObject, public Dependency, public ScriptInitializerMixin { +class ScriptEngines : public QObject, public Dependency, public ScriptInitializerMixin { Q_OBJECT Q_PROPERTY(ScriptsModel* scriptsModel READ scriptsModel CONSTANT) @@ -58,8 +58,8 @@ class ScriptEngines : public QObject, public Dependency, public ScriptInitialize Q_PROPERTY(QString debugScriptUrl READ getDebugScriptUrl WRITE setDebugScriptUrl) public: - ScriptEngines(ScriptEngine::Context context, const QUrl& defaultScriptsOverride = QUrl()); - int runScriptInitializers(ScriptEnginePointer engine) override; + ScriptEngines(ScriptManager::Context context, const QUrl& defaultScriptsOverride = QUrl()); + int runScriptInitializers(ScriptManagerPointer manager) override; void loadScripts(); void saveScripts(); @@ -71,7 +71,7 @@ class ScriptEngines : public QObject, public Dependency, public ScriptInitialize void reloadLocalFiles(); QStringList getRunningScripts(); - ScriptEnginePointer getScriptEngine(const QUrl& scriptHash); + ScriptManagerPointer getScriptEngine(const QUrl& scriptHash); ScriptsModel* scriptsModel() { return &_scriptsModel; }; ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; }; @@ -107,7 +107,7 @@ class ScriptEngines : public QObject, public Dependency, public ScriptInitialize * false to not close Interface. * @returns {object} An empty object, {}. */ - Q_INVOKABLE ScriptEnginePointer loadScript(const QUrl& scriptFilename = QString(), + Q_INVOKABLE ScriptManagerPointer loadScript(const QUrl& scriptFilename = QString(), bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false, bool quitWhenFinished = false); /**jsdoc @@ -176,7 +176,7 @@ class ScriptEngines : public QObject, public Dependency, public ScriptInitialize void shutdownScripting(); bool isStopped() const { return _isStopped; } - void addScriptEngine(ScriptEnginePointer); + void addScriptEngine(ScriptManagerPointer); ScriptGatekeeper scriptGatekeeper; @@ -322,26 +322,24 @@ protected slots: /**jsdoc * @function ScriptDiscoveryService.onScriptFinished * @param {string} scriptName - Script name. - * @param {object} engine - Engine. + * @param {object} manager - Script manager. * @deprecated This function is deprecated and will be removed. */ // Deprecated because it wasn't intended to be in the API. - void onScriptFinished(const QString& fileNameString, ScriptEnginePointer engine); + void onScriptFinished(const QString& fileNameString, ScriptManagerPointer manager); protected: - friend class ScriptEngine; - - ScriptEnginePointer reloadScript(const QString& scriptName, bool isUserLoaded = true) { return loadScript(scriptName, isUserLoaded, false, false, true); } - void removeScriptEngine(ScriptEnginePointer); + ScriptManagerPointer reloadScript(const QString& scriptName, bool isUserLoaded = true) { return loadScript(scriptName, isUserLoaded, false, false, true); } + void removeScriptEngine(ScriptManagerPointer); void onScriptEngineLoaded(const QString& scriptFilename); void quitWhenFinished(); void onScriptEngineError(const QString& scriptFilename); - void launchScriptEngine(ScriptEnginePointer); + void launchScriptEngine(ScriptManagerPointer); - ScriptEngine::Context _context; - QReadWriteLock _scriptEnginesHashLock; - QHash _scriptEnginesHash; - QSet _allKnownScriptEngines; + ScriptManager::Context _context; + QReadWriteLock _scriptManagersHashLock; + QHash _scriptManagersHash; + QSet _allKnownScriptManagers; QMutex _allScriptsMutex; ScriptsModel _scriptsModel; ScriptsModelFilter _scriptsModelFilter; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptManager.cpp similarity index 66% rename from libraries/script-engine/src/ScriptEngine.cpp rename to libraries/script-engine/src/ScriptManager.cpp index 9fbf7a28015..24474e9fb38 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -1,5 +1,5 @@ // -// ScriptEngine.cpp +// ScriptManager.cpp // libraries/script-engine/src // // Created by Brad Hefta-Gaub on 12/14/13. @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ScriptEngine.h" +#include "ScriptManager.h" #include #include @@ -32,12 +32,6 @@ #include #include -#include -#include -#include - -#include - #include #include #include @@ -60,9 +54,9 @@ #include #include "ArrayBufferViewClass.h" +#include "AudioScriptingInterface.h" #include "AssetScriptingInterface.h" #include "BatchLoader.h" -#include "BaseScriptEngine.h" #include "DataViewClass.h" #include "EventTypes.h" #include "FileScriptingInterface.h" // unzip project @@ -70,6 +64,8 @@ #include "ScriptAudioInjector.h" #include "ScriptAvatarData.h" #include "ScriptCache.h" +#include "ScriptContext.h" +#include "ScriptEngineCast.h" #include "ScriptEngineLogging.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" @@ -78,6 +74,8 @@ #include "ScriptEngines.h" #include "StackTestScriptingInterface.h" #include "ModelScriptingInterface.h" +#include "ScriptValue.h" +#include "ScriptValueIterator.h" #include @@ -89,58 +87,61 @@ #include #include -const QString ScriptEngine::_SETTINGS_ENABLE_EXTENDED_EXCEPTIONS { +const QString ScriptManager::_SETTINGS_ENABLE_EXTENDED_EXCEPTIONS { "com.highfidelity.experimental.enableExtendedJSExceptions" }; +const QString ScriptManager::SCRIPT_EXCEPTION_FORMAT{ "[%0] %1 in %2:%3" }; +const QString ScriptManager::SCRIPT_BACKTRACE_SEP{ "\n " }; + static const int MAX_MODULE_ID_LENGTH { 4096 }; static const int MAX_DEBUG_VALUE_LENGTH { 80 }; -static const QScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = - QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects; -static const QScriptValue::PropertyFlags READONLY_PROP_FLAGS { QScriptValue::ReadOnly | QScriptValue::Undeletable }; -static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_PROP_FLAGS | QScriptValue::SkipInEnumeration }; +static const ScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = + ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects; +static const ScriptValue::PropertyFlags READONLY_PROP_FLAGS{ ScriptValue::ReadOnly | ScriptValue::Undeletable }; +static const ScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS{ READONLY_PROP_FLAGS | ScriptValue::SkipInEnumeration }; static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; -Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) -int functionSignatureMetaID = qRegisterMetaType(); +Q_DECLARE_METATYPE(ScriptEngine::FunctionSignature) +int functionSignatureMetaID = qRegisterMetaType(); -int scriptEnginePointerMetaID = qRegisterMetaType(); +int scriptManagerPointerMetaID = qRegisterMetaType(); Q_DECLARE_METATYPE(ExternalResource::Bucket); -static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { +static ScriptValuePointer debugPrint(ScriptContext* context, ScriptEngine* engine) { // assemble the message by concatenating our arguments QString message = ""; for (int i = 0; i < context->argumentCount(); i++) { if (i > 0) { message += " "; } - message += context->argument(i).toString(); + message += context->argument(i)->toString(); } // was this generated by a script engine? If we don't recognize it then send the message and exit - ScriptEngine* scriptEngine = qobject_cast(engine); - if (!scriptEngine) { + ScriptManager* scriptManager = engine->manager(); + if (!scriptManager) { qCDebug(scriptengine_script, "%s", qUtf8Printable(message)); - return QScriptValue(); + return ScriptValuePointer(); } // This message was sent by one of our script engines, let's try to see if we can find the source. // Note that the first entry in the backtrace should be "print" and is somewhat useless to us AbstractLoggerInterface* loggerInterface = AbstractLoggerInterface::get(); if (loggerInterface && loggerInterface->showSourceDebugging()) { - QScriptContext* userContext = context; - while (userContext && QScriptContextInfo(userContext).functionType() == QScriptContextInfo::NativeFunction) { + ScriptContext* userContext = context; + while (userContext && userContext->functionContext()->functionType() == ScriptFunctionContext::NativeFunction) { userContext = userContext->parentContext(); } QString location; if (userContext) { - QScriptContextInfo contextInfo(userContext); - QString fileName = contextInfo.fileName(); - int lineNumber = contextInfo.lineNumber(); - QString functionName = contextInfo.functionName(); + auto contextInfo = userContext->functionContext(); + QString fileName = contextInfo->fileName(); + int lineNumber = contextInfo->lineNumber(); + QString functionName = contextInfo->functionName(); location = functionName; if (!fileName.isEmpty()) { @@ -155,32 +156,32 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { } } if (location.isEmpty()) { - location = scriptEngine->getFilename(); + location = scriptManager->getFilename(); } // give the script engine a chance to notify the system about this message - scriptEngine->print(message); + scriptManager->print(message); // send the message to debug log qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(location), qUtf8Printable(message)); } else { - scriptEngine->print(message); + scriptManager->print(message); // prefix the script engine name to help disambiguate messages in the main debug log - qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(scriptEngine->getFilename()), qUtf8Printable(message)); + qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(scriptManager->getFilename()), qUtf8Printable(message)); } - return QScriptValue(); + return ScriptValuePointer(); } Q_DECLARE_METATYPE(controller::InputController*) //static int inputControllerPointerId = qRegisterMetaType(); -QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) { - return engine->newQObject(in, QScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); +ScriptValuePointer inputControllerToScriptValue(ScriptEngine* engine, controller::InputController* const& in) { + return engine->newQObject(in, ScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); } -void inputControllerFromScriptValue(const QScriptValue &object, controller::InputController* &out) { - out = qobject_cast(object.toQObject()); +void inputControllerFromScriptValue(const ScriptValuePointer& object, controller::InputController*& out) { + out = qobject_cast(object->toQObject()); } // FIXME Come up with a way to properly encode entity IDs in filename @@ -203,32 +204,40 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID) return url + " [EntityID:" + entityID + "]"; } -QString ScriptEngine::logException(const QScriptValue& exception) { +QString ScriptManager::logException(const ScriptValuePointer& exception) { auto message = formatException(exception, _enableExtendedJSExceptions.get()); scriptErrorMessage(message); return message; } -ScriptEnginePointer scriptEngineFactory(ScriptEngine::Context context, +ScriptManagerPointer scriptManagerFactory(ScriptManager::Context context, const QString& scriptContents, const QString& fileNameString) { - ScriptEngine* engine = new ScriptEngine(context, scriptContents, fileNameString); - ScriptEnginePointer engineSP = ScriptEnginePointer(engine, &QObject::deleteLater); + ScriptManagerPointer manager = newScriptManager(context, scriptContents, fileNameString); auto scriptEngines = DependencyManager::get(); - scriptEngines->addScriptEngine(qSharedPointerCast(engineSP)); - engine->setScriptEngines(scriptEngines); - return engineSP; + scriptEngines->addScriptEngine(manager); + manager->setScriptEngines(scriptEngines); + return manager; +} + +ScriptManagerPointer newScriptManager(ScriptManager::Context context, + const QString& scriptContents, + const QString& fileNameString) { + ScriptManagerPointer manager(new ScriptManager(context, scriptContents, fileNameString), &QObject::deleteLater); + ScriptEnginePointer engine = newScriptEngine(manager.get()); + manager->_engine = engine; + return manager; } -int ScriptEngine::processLevelMaxRetries { ScriptRequest::MAX_RETRIES }; -ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const QString& fileNameString) : - BaseScriptEngine(), +int ScriptManager::processLevelMaxRetries { ScriptRequest::MAX_RETRIES }; +ScriptManager::ScriptManager(Context context, const QString& scriptContents, const QString& fileNameString) : + QObject(), _context(context), _scriptContents(scriptContents), _timerFunctionMap(), _fileNameString(fileNameString), - _arrayBufferClass(new ArrayBufferClass(this)), - _assetScriptingInterface(new AssetScriptingInterface(this)) + _assetScriptingInterface(new AssetScriptingInterface(this)), + _engine(newScriptEngine(this)) { switch (_context) { case Context::CLIENT_SCRIPT: @@ -245,34 +254,22 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const break; } - connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { - if (hasUncaughtException()) { - // the engine's uncaughtException() seems to produce much better stack traces here - emit unhandledException(cloneUncaughtException("signalHandlerException")); - clearExceptions(); - } else { - // ... but may not always be available -- so if needed we fallback to the passed exception - emit unhandledException(exception); - } - }, Qt::DirectConnection); - - setProcessEventsInterval(MSECS_PER_SECOND); if (isEntityServerScript()) { qCDebug(scriptengine) << "isEntityServerScript() -- limiting maxRetries to 1"; processLevelMaxRetries = 1; } // this is where all unhandled exceptions end up getting logged - connect(this, &BaseScriptEngine::unhandledException, this, [this](const QScriptValue& err) { - auto output = err.engine() == this ? err : makeError(err); - if (!output.property("detail").isValid()) { - output.setProperty("detail", "UnhandledException"); + connect(this, &ScriptManager::unhandledException, this, [this](const ScriptValuePointer& err) { + auto output = err->engine() == _engine ? err : _engine->makeError(err); + if (!output->property("detail")->isValid()) { + output->setProperty("detail", "UnhandledException"); } logException(output); }); if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { - QObject::connect(this, &ScriptEngine::update, this, [this]() { + QObject::connect(this, &ScriptManager::update, this, [this]() { // process pending entity script content if (!_contentAvailableQueue.empty() && !(_isFinished || _isStopping)) { EntityScriptContentAvailableMap pending; @@ -286,12 +283,12 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const } } -QString ScriptEngine::getTypeAsString() const { +QString ScriptManager::getTypeAsString() const { auto value = QVariant::fromValue(_type).toString(); return value.isEmpty() ? "unknown" : value.toLower(); } -QString ScriptEngine::getContext() const { +QString ScriptManager::getContext() const { switch (_context) { case CLIENT_SCRIPT: return "client"; @@ -307,7 +304,7 @@ QString ScriptEngine::getContext() const { return "unknown"; } -bool ScriptEngine::isDebugMode() const { +bool ScriptManager::isDebugMode() const { #if defined(DEBUG) return true; #else @@ -315,9 +312,9 @@ bool ScriptEngine::isDebugMode() const { #endif } -ScriptEngine::~ScriptEngine() {} +ScriptManager::~ScriptManager() {} -void ScriptEngine::disconnectNonEssentialSignals() { +void ScriptManager::disconnectNonEssentialSignals() { disconnect(); QThread* workerThread; // Ensure the thread should be running, and does exist @@ -327,8 +324,8 @@ void ScriptEngine::disconnectNonEssentialSignals() { } } -void ScriptEngine::runDebuggable() { - static QMenuBar* menuBar { nullptr }; +void ScriptManager::runDebuggable() { + static QMenuBar* menuBar{ nullptr }; static QMenu* scriptDebugMenu { nullptr }; static size_t scriptMenuCount { 0 }; if (!scriptDebugMenu) { @@ -348,7 +345,7 @@ void ScriptEngine::runDebuggable() { _isRunning = true; _debuggable = true; _debugger = new QScriptEngineDebugger(this); - _debugger->attachTo(this); + _debugger->attachTo(_engine); QMenu* parentMenu = scriptDebugMenu; QMenu* scriptMenu { nullptr }; @@ -360,11 +357,11 @@ void ScriptEngine::runDebuggable() { qWarning() << "Unable to add script debug menu"; } - QScriptValue result = evaluate(_scriptContents, _fileNameString); + ScriptValuePointer result = _engine->evaluate(_scriptContents, _fileNameString); _lastUpdate = usecTimestampNow(); QTimer* timer = new QTimer(this); - connect(this, &ScriptEngine::finished, [this, timer, parentMenu, scriptMenu] { + connect(this, &ScriptManager::finished, [this, timer, parentMenu, scriptMenu] { if (scriptMenu) { parentMenu->removeAction(scriptMenu->menuAction()); --scriptMenuCount; @@ -384,7 +381,7 @@ void ScriptEngine::runDebuggable() { stopAllTimers(); // make sure all our timers are stopped if the script is ending emit scriptEnding(); - emit finished(_fileNameString, qSharedPointerCast(sharedFromThis())); + emit finished(_fileNameString, qSharedPointerCast(sharedFromThis())); _isRunning = false; emit runningStateChanged(); @@ -405,11 +402,11 @@ void ScriptEngine::runDebuggable() { _lastUpdate = now; // only clear exceptions if we are not in the middle of evaluating - if (!isEvaluating() && hasUncaughtException()) { + if (!_engine->isEvaluating() && _engine->hasUncaughtException()) { qCWarning(scriptengine) << __FUNCTION__ << "---------- UNCAUGHT EXCEPTION --------"; - qCWarning(scriptengine) << "runDebuggable" << uncaughtException().toString(); - logException(__FUNCTION__); - clearExceptions(); + qCWarning(scriptengine) << "runDebuggable" << _engine->uncaughtException()->toString(); + logException(_engine->newValue(__FUNCTION__)); + _engine->clearExceptions(); } }); @@ -417,8 +414,8 @@ void ScriptEngine::runDebuggable() { } -void ScriptEngine::runInThread() { - Q_ASSERT_X(!_isThreaded, "ScriptEngine::runInThread()", "runInThread should not be called more than once"); +void ScriptManager::runInThread() { + Q_ASSERT_X(!_isThreaded, "ScriptManager::runInThread()", "runInThread should not be called more than once"); if (_isThreaded) { return; @@ -446,7 +443,7 @@ void ScriptEngine::runInThread() { workerThread->start(); } -void ScriptEngine::executeOnScriptThread(std::function function, const Qt::ConnectionType& type ) { +void ScriptManager::executeOnScriptThread(std::function function, const Qt::ConnectionType& type ) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "executeOnScriptThread", type, Q_ARG(std::function, function)); return; @@ -455,14 +452,14 @@ void ScriptEngine::executeOnScriptThread(std::function function, const Q function(); } -void ScriptEngine::waitTillDoneRunning(bool shutdown) { +void ScriptManager::waitTillDoneRunning(bool shutdown) { // Engine should be stopped already, but be defensive stop(); auto workerThread = thread(); if (workerThread == QThread::currentThread()) { - qCWarning(scriptengine) << "ScriptEngine::waitTillDoneRunning called, but the script is on the same thread:" << getFilename(); + qCWarning(scriptengine) << "ScriptManager::waitTillDoneRunning called, but the script is on the same thread:" << getFilename(); return; } @@ -481,11 +478,11 @@ void ScriptEngine::waitTillDoneRunning(bool shutdown) { if (workerThread->isRunning()) { workerThread->quit(); - if (isEvaluating()) { + if (_engine->isEvaluating()) { qCWarning(scriptengine) << "Script Engine has been running too long, aborting:" << getFilename(); - abortEvaluation(); + _engine->abortEvaluation(); } else { - auto context = currentContext(); + auto context = _engine->currentContext(); if (context) { qCWarning(scriptengine) << "Script Engine has been running too long, throwing:" << getFilename(); context->throwError("Timed out during shutdown"); @@ -508,11 +505,11 @@ void ScriptEngine::waitTillDoneRunning(bool shutdown) { if (elapsedUsecs > MAX_SCRIPT_EVALUATION_TIME) { workerThread->quit(); - if (isEvaluating()) { + if (_engine->isEvaluating()) { qCWarning(scriptengine) << "Script Engine has been running too long, aborting:" << getFilename(); - abortEvaluation(); + _engine->abortEvaluation(); } else { - auto context = currentContext(); + auto context = _engine->currentContext(); if (context) { qCWarning(scriptengine) << "Script Engine has been running too long, throwing:" << getFilename(); context->throwError("Timed out during shutdown"); @@ -545,7 +542,7 @@ void ScriptEngine::waitTillDoneRunning(bool shutdown) { } } -QString ScriptEngine::getFilename() const { +QString ScriptManager::getFilename() const { QStringList fileNameParts = _fileNameString.split("/"); QString lastPart; if (!fileNameParts.isEmpty()) { @@ -554,13 +551,13 @@ QString ScriptEngine::getFilename() const { return lastPart; } -bool ScriptEngine::hasValidScriptSuffix(const QString& scriptFileName) { +bool ScriptManager::hasValidScriptSuffix(const QString& scriptFileName) { QFileInfo fileInfo(scriptFileName); QString scriptSuffixToLower = fileInfo.completeSuffix().toLower(); return scriptSuffixToLower.contains(QString("js"), Qt::CaseInsensitive); } -void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { +void ScriptManager::loadURL(const QUrl& scriptURL, bool reload) { if (_isRunning) { return; } @@ -598,48 +595,48 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { }, reload, maxRetries); } -void ScriptEngine::scriptErrorMessage(const QString& message) { +void ScriptManager::scriptErrorMessage(const QString& message) { qCCritical(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message)); emit errorMessage(message, getFilename()); } -void ScriptEngine::scriptWarningMessage(const QString& message) { +void ScriptManager::scriptWarningMessage(const QString& message) { qCWarning(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message)); emit warningMessage(message, getFilename()); } -void ScriptEngine::scriptInfoMessage(const QString& message) { +void ScriptManager::scriptInfoMessage(const QString& message) { qCInfo(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message)); emit infoMessage(message, getFilename()); } -void ScriptEngine::scriptPrintedMessage(const QString& message) { +void ScriptManager::scriptPrintedMessage(const QString& message) { qCDebug(scriptengine, "[%s] %s", qUtf8Printable(getFilename()), qUtf8Printable(message)); emit printedMessage(message, getFilename()); } -void ScriptEngine::clearDebugLogWindow() { +void ScriptManager::clearDebugLogWindow() { emit clearDebugWindow(); } // Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of // callAnimationStateHandler requires that the type be registered. // These two are meaningful, if we ever do want to use them... -static QScriptValue animVarMapToScriptValue(QScriptEngine* engine, const AnimVariantMap& parameters) { +static ScriptValuePointer animVarMapToScriptValue(ScriptEngine* engine, const AnimVariantMap& parameters) { QStringList unused; return parameters.animVariantMapToScriptValue(engine, unused, false); } -static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap& parameters) { +static void animVarMapFromScriptValue(const ScriptValuePointer& value, AnimVariantMap& parameters) { parameters.animVariantMapFromScriptValue(value); } // ... while these two are not. But none of the four are ever used. -static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine, +static ScriptValuePointer resultHandlerToScriptValue(ScriptEngine* engine, const AnimVariantResultHandler& resultHandler) { qCCritical(scriptengine) << "Attempt to marshall result handler to javascript"; assert(false); - return QScriptValue(); + return ScriptValuePointer(); } -static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantResultHandler& resultHandler) { +static void resultHandlerFromScriptValue(const ScriptValuePointer& value, AnimVariantResultHandler& resultHandler) { qCCritical(scriptengine) << "Attempt to marshall result handler from javascript"; assert(false); } @@ -647,10 +644,10 @@ static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantR // Templated qScriptRegisterMetaType fails to compile with raw pointers using ScriptableResourceRawPtr = ScriptableResource*; -static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine, +static ScriptValuePointer scriptableResourceToScriptValue(ScriptEngine* engine, const ScriptableResourceRawPtr& resource) { if (!resource) { - return QScriptValue(); // probably shutting down + return ScriptValuePointer(); // probably shutting down } // The first script to encounter this resource will track its memory. @@ -666,13 +663,13 @@ static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine, auto object = engine->newQObject( const_cast(resource), - QScriptEngine::ScriptOwnership, + ScriptEngine::ScriptOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); return object; } -static void scriptableResourceFromScriptValue(const QScriptValue& value, ScriptableResourceRawPtr& resource) { - resource = static_cast(value.toQObject()); +static void scriptableResourceFromScriptValue(const ScriptValuePointer& value, ScriptableResourceRawPtr& resource) { + resource = static_cast(value->toQObject()); } /**jsdoc @@ -688,114 +685,116 @@ static void scriptableResourceFromScriptValue(const QScriptValue& value, Scripta * * @property {Resource.State} State - The possible loading states of a resource. Read-only. */ -static QScriptValue createScriptableResourcePrototype(ScriptEnginePointer engine) { +static ScriptValuePointer createScriptableResourcePrototype(ScriptManagerPointer manager) { + auto engine = manager->engine(); auto prototype = engine->newObject(); // Expose enum State to JS/QML via properties - QObject* state = new QObject(engine.data()); + QObject* state = new QObject(manager.data()); state->setObjectName("ResourceState"); auto metaEnum = QMetaEnum::fromType(); for (int i = 0; i < metaEnum.keyCount(); ++i) { state->setProperty(metaEnum.key(i), metaEnum.value(i)); } - auto prototypeState = engine->newQObject(state, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeSlots | QScriptEngine::ExcludeSuperClassMethods); - prototype.setProperty("State", prototypeState); + auto prototypeState = engine->newQObject(state, ScriptEngine::QtOwnership, + ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeSlots | ScriptEngine::ExcludeSuperClassMethods); + prototype->setProperty("State", prototypeState); return prototype; } -QScriptValue avatarDataToScriptValue(QScriptEngine* engine, ScriptAvatarData* const& in) { - return engine->newQObject(in, QScriptEngine::ScriptOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); +ScriptValuePointer avatarDataToScriptValue(ScriptEngine* engine, ScriptAvatarData* const& in) { + return engine->newQObject(in, ScriptEngine::ScriptOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); } -void avatarDataFromScriptValue(const QScriptValue& object, ScriptAvatarData*& out) { +void avatarDataFromScriptValue(const ScriptValuePointer& object, ScriptAvatarData*& out) { // This is not implemented because there are no slots/properties that take an AvatarSharedPointer from a script assert(false); out = nullptr; } -QScriptValue externalResourceBucketToScriptValue(QScriptEngine* engine, ExternalResource::Bucket const& in) { - return QScriptValue((int)in); +ScriptValuePointer externalResourceBucketToScriptValue(ScriptEngine* engine, ExternalResource::Bucket const& in) { + return engine->newValue((int)in); } -void externalResourceBucketFromScriptValue(const QScriptValue& object, ExternalResource::Bucket& out) { - out = static_cast(object.toInt32()); +void externalResourceBucketFromScriptValue(const ScriptValuePointer& object, ExternalResource::Bucket& out) { + out = static_cast(object->toInt32()); } -void ScriptEngine::resetModuleCache(bool deleteScriptCache) { +void ScriptManager::resetModuleCache(bool deleteScriptCache) { if (QThread::currentThread() != thread()) { executeOnScriptThread([=]() { resetModuleCache(deleteScriptCache); }); return; } - auto jsRequire = globalObject().property("Script").property("require"); - auto cache = jsRequire.property("cache"); - auto cacheMeta = jsRequire.data(); + auto jsRequire = _engine->globalObject()->property("Script")->property("require"); + auto cache = jsRequire->property("cache"); + auto cacheMeta = jsRequire->data(); if (deleteScriptCache) { - QScriptValueIterator it(cache); - while (it.hasNext()) { - it.next(); - if (it.flags() & QScriptValue::SkipInEnumeration) { + auto it = cache->newIterator(); + while (it->hasNext()) { + it->next(); + if (it->flags() & ScriptValue::SkipInEnumeration) { continue; } - qCDebug(scriptengine) << "resetModuleCache(true) -- staging " << it.name() << " for cache reset at next require"; - cacheMeta.setProperty(it.name(), true); + qCDebug(scriptengine) << "resetModuleCache(true) -- staging " << it->name() << " for cache reset at next require"; + cacheMeta->setProperty(it->name(), true); } } - cache = newObject(); - if (!cacheMeta.isObject()) { - cacheMeta = newObject(); - cacheMeta.setProperty("id", "Script.require.cacheMeta"); - cacheMeta.setProperty("type", "cacheMeta"); - jsRequire.setData(cacheMeta); + cache = _engine->newObject(); + if (!cacheMeta->isObject()) { + cacheMeta = _engine->newObject(); + cacheMeta->setProperty("id", "Script.require.cacheMeta"); + cacheMeta->setProperty("type", "cacheMeta"); + jsRequire->setData(cacheMeta); } - cache.setProperty("__created__", (double)QDateTime::currentMSecsSinceEpoch(), QScriptValue::SkipInEnumeration); + cache->setProperty("__created__", (double)QDateTime::currentMSecsSinceEpoch(), ScriptValue::SkipInEnumeration); #if DEBUG_JS_MODULES cache.setProperty("__meta__", cacheMeta, READONLY_HIDDEN_PROP_FLAGS); #endif - jsRequire.setProperty("cache", cache, READONLY_PROP_FLAGS); + jsRequire->setProperty("cache", cache, READONLY_PROP_FLAGS); } -void ScriptEngine::init() { +void ScriptManager::init() { if (_isInitialized) { return; // only initialize once } _isInitialized = true; + auto scriptEngine = _engine.data(); auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->init(); // register various meta-types - registerMetaTypes(this); - registerMIDIMetaTypes(this); - registerEventTypes(this); - registerMenuItemProperties(this); - registerAnimationTypes(this); - registerAvatarTypes(this); - registerAudioMetaTypes(this); - - qScriptRegisterMetaType(this, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue); - qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); - qScriptRegisterMetaType(this, EntityPropertyInfoToScriptValue, EntityPropertyInfoFromScriptValue); - qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); - qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); - qScriptRegisterMetaType(this, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue); - qScriptRegisterMetaType(this, AvatarEntityMapToScriptValue, AvatarEntityMapFromScriptValue); - qScriptRegisterSequenceMetaType>(this); - qScriptRegisterSequenceMetaType>(this); - - qScriptRegisterSequenceMetaType>(this); - qScriptRegisterSequenceMetaType>(this); - qScriptRegisterSequenceMetaType>(this); - - QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); - globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); - - QScriptValue webSocketConstructorValue = newFunction(WebSocketClass::constructor); - globalObject().setProperty("WebSocket", webSocketConstructorValue); + registerMetaTypes(scriptEngine); + registerMIDIMetaTypes(scriptEngine); + registerEventTypes(scriptEngine); + registerMenuItemProperties(scriptEngine); + registerAnimationTypes(scriptEngine); + registerAvatarTypes(scriptEngine); + registerAudioMetaTypes(scriptEngine); + + scriptRegisterMetaType(scriptEngine, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue); + scriptRegisterMetaType(scriptEngine, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); + scriptRegisterMetaType(scriptEngine, EntityPropertyInfoToScriptValue, EntityPropertyInfoFromScriptValue); + scriptRegisterMetaType(scriptEngine, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); + scriptRegisterMetaType(scriptEngine, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); + scriptRegisterMetaType(scriptEngine, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue); + scriptRegisterMetaType(scriptEngine, AvatarEntityMapToScriptValue, AvatarEntityMapFromScriptValue); + scriptRegisterSequenceMetaType>(scriptEngine); + scriptRegisterSequenceMetaType>(scriptEngine); + + scriptRegisterSequenceMetaType>(scriptEngine); + scriptRegisterSequenceMetaType>(scriptEngine); + scriptRegisterSequenceMetaType>(scriptEngine); + + ScriptValuePointer xmlHttpRequestConstructorValue = scriptEngine->newFunction(XMLHttpRequestClass::constructor); + scriptEngine->globalObject()->setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); + + ScriptValuePointer webSocketConstructorValue = scriptEngine->newFunction(WebSocketClass::constructor); + scriptEngine->globalObject()->setProperty("WebSocket", webSocketConstructorValue); /**jsdoc * Prints a message to the program log and emits {@link Script.printedMessage}. @@ -804,249 +803,109 @@ void ScriptEngine::init() { * @function print * @param {...*} [message] - The message values to print. */ - globalObject().setProperty("print", newFunction(debugPrint)); + scriptEngine->globalObject()->setProperty("print", scriptEngine->newFunction(debugPrint)); - QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); - globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); + ScriptValuePointer audioEffectOptionsConstructorValue = scriptEngine->newFunction(AudioEffectOptions::constructor); + scriptEngine->globalObject()->setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); - qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); - qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); - qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue); - qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue); - qScriptRegisterMetaType(this, webSocketToScriptValue, webSocketFromScriptValue); - qScriptRegisterMetaType(this, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue); - qScriptRegisterMetaType(this, wscReadyStateToScriptValue, wscReadyStateFromScriptValue); + scriptRegisterMetaType(scriptEngine, injectorToScriptValue, injectorFromScriptValue); + scriptRegisterMetaType(scriptEngine, inputControllerToScriptValue, inputControllerFromScriptValue); + scriptRegisterMetaType(scriptEngine, avatarDataToScriptValue, avatarDataFromScriptValue); + scriptRegisterMetaType(scriptEngine, animationDetailsToScriptValue, animationDetailsFromScriptValue); + scriptRegisterMetaType(scriptEngine, webSocketToScriptValue, webSocketFromScriptValue); + scriptRegisterMetaType(scriptEngine, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue); + scriptRegisterMetaType(scriptEngine, wscReadyStateToScriptValue, wscReadyStateFromScriptValue); - // NOTE: You do not want to end up creating new instances of singletons here. They will be on the ScriptEngine thread - // and are likely to be unusable if we "reset" the ScriptEngine by creating a new one (on a whole new thread). + // NOTE: You do not want to end up creating new instances of singletons here. They will be on the ScriptManager thread + // and are likely to be unusable if we "reset" the ScriptManager by creating a new one (on a whole new thread). - registerGlobalObject("Script", this); + scriptEngine->registerGlobalObject("Script", this); { // set up Script.require.resolve and Script.require.cache - auto Script = globalObject().property("Script"); - auto require = Script.property("require"); - auto resolve = Script.property("_requireResolve"); - require.setProperty("resolve", resolve, READONLY_PROP_FLAGS); + auto Script = scriptEngine->globalObject()->property("Script"); + auto require = Script->property("require"); + auto resolve = Script->property("_requireResolve"); + require->setProperty("resolve", resolve, READONLY_PROP_FLAGS); resetModuleCache(); } - qScriptRegisterMetaType(this, externalResourceBucketToScriptValue, externalResourceBucketFromScriptValue); - registerEnum("Script.ExternalPaths", QMetaEnum::fromType()); - - registerGlobalObject("Audio", DependencyManager::get().data()); - - registerGlobalObject("Midi", DependencyManager::get().data()); - - registerGlobalObject("Entities", entityScriptingInterface.data()); - registerFunction("Entities", "getMultipleEntityProperties", EntityScriptingInterface::getMultipleEntityProperties); - registerGlobalObject("Quat", &_quatLibrary); - registerGlobalObject("Vec3", &_vec3Library); - registerGlobalObject("Mat4", &_mat4Library); - registerGlobalObject("Uuid", &_uuidLibrary); - registerGlobalObject("Messages", DependencyManager::get().data()); - registerGlobalObject("File", new FileScriptingInterface(this)); - registerGlobalObject("console", &_consoleScriptingInterface); - registerFunction("console", "info", ConsoleScriptingInterface::info, currentContext()->argumentCount()); - registerFunction("console", "log", ConsoleScriptingInterface::log, currentContext()->argumentCount()); - registerFunction("console", "debug", ConsoleScriptingInterface::debug, currentContext()->argumentCount()); - registerFunction("console", "warn", ConsoleScriptingInterface::warn, currentContext()->argumentCount()); - registerFunction("console", "error", ConsoleScriptingInterface::error, currentContext()->argumentCount()); - registerFunction("console", "exception", ConsoleScriptingInterface::exception, currentContext()->argumentCount()); - registerFunction("console", "assert", ConsoleScriptingInterface::assertion, currentContext()->argumentCount()); - registerFunction("console", "group", ConsoleScriptingInterface::group, 1); - registerFunction("console", "groupCollapsed", ConsoleScriptingInterface::groupCollapsed, 1); - registerFunction("console", "groupEnd", ConsoleScriptingInterface::groupEnd, 0); - - qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue); - qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue); + scriptRegisterMetaType(scriptEngine, externalResourceBucketToScriptValue, externalResourceBucketFromScriptValue); + scriptEngine->registerEnum("Script.ExternalPaths", QMetaEnum::fromType()); + + scriptEngine->registerGlobalObject("Audio", DependencyManager::get().data()); + + scriptEngine->registerGlobalObject("Midi", DependencyManager::get().data()); + + scriptEngine->registerGlobalObject("Entities", entityScriptingInterface.data()); + scriptEngine->registerFunction("Entities", "getMultipleEntityProperties", + EntityScriptingInterface::getMultipleEntityProperties); + scriptEngine->registerGlobalObject("Quat", &_quatLibrary); + scriptEngine->registerGlobalObject("Vec3", &_vec3Library); + scriptEngine->registerGlobalObject("Mat4", &_mat4Library); + scriptEngine->registerGlobalObject("Uuid", &_uuidLibrary); + scriptEngine->registerGlobalObject("Messages", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("File", new FileScriptingInterface(this)); + scriptEngine->registerGlobalObject("console", &_consoleScriptingInterface); + scriptEngine->registerFunction("console", "info", ConsoleScriptingInterface::info, scriptEngine->currentContext()->argumentCount()); + scriptEngine->registerFunction("console", "log", ConsoleScriptingInterface::log, scriptEngine->currentContext()->argumentCount()); + scriptEngine->registerFunction("console", "debug", ConsoleScriptingInterface::debug, scriptEngine->currentContext()->argumentCount()); + scriptEngine->registerFunction("console", "warn", ConsoleScriptingInterface::warn, scriptEngine->currentContext()->argumentCount()); + scriptEngine->registerFunction("console", "error", ConsoleScriptingInterface::error, scriptEngine->currentContext()->argumentCount()); + scriptEngine->registerFunction("console", "exception", ConsoleScriptingInterface::exception, scriptEngine->currentContext()->argumentCount()); + scriptEngine->registerFunction("console", "assert", ConsoleScriptingInterface::assertion, scriptEngine->currentContext()->argumentCount()); + scriptEngine->registerFunction("console", "group", ConsoleScriptingInterface::group, 1); + scriptEngine->registerFunction("console", "groupCollapsed", ConsoleScriptingInterface::groupCollapsed, 1); + scriptEngine->registerFunction("console", "groupEnd", ConsoleScriptingInterface::groupEnd, 0); + + scriptRegisterMetaType(scriptEngine, animVarMapToScriptValue, animVarMapFromScriptValue); + scriptRegisterMetaType(scriptEngine, resultHandlerToScriptValue, resultHandlerFromScriptValue); // Scriptable cache access - auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast(sharedFromThis())); - globalObject().setProperty("Resource", resourcePrototype); - setDefaultPrototype(qMetaTypeId(), resourcePrototype); - qScriptRegisterMetaType(this, scriptableResourceToScriptValue, scriptableResourceFromScriptValue); + auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast(sharedFromThis())); + scriptEngine->globalObject()->setProperty("Resource", resourcePrototype); + scriptEngine->setDefaultPrototype(qMetaTypeId(), resourcePrototype); + scriptRegisterMetaType(scriptEngine, scriptableResourceToScriptValue, scriptableResourceFromScriptValue); // constants - globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); + scriptEngine->globalObject()->setProperty("TREE_SCALE", scriptEngine->newValue(TREE_SCALE)); - registerGlobalObject("Assets", _assetScriptingInterface); - registerGlobalObject("Resources", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Assets", _assetScriptingInterface); + scriptEngine->registerGlobalObject("Resources", DependencyManager::get().data()); - registerGlobalObject("DebugDraw", &DebugDraw::getInstance()); + scriptEngine->registerGlobalObject("DebugDraw", &DebugDraw::getInstance()); - registerGlobalObject("Model", new ModelScriptingInterface(this)); - qScriptRegisterMetaType(this, meshToScriptValue, meshFromScriptValue); - qScriptRegisterMetaType(this, meshesToScriptValue, meshesFromScriptValue); + scriptEngine->registerGlobalObject("Model", new ModelScriptingInterface(this)); + scriptRegisterMetaType(scriptEngine, meshToScriptValue, meshFromScriptValue); + scriptRegisterMetaType(scriptEngine, meshesToScriptValue, meshesFromScriptValue); - registerGlobalObject("UserActivityLogger", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get().data()); #if DEV_BUILD || PR_BUILD - registerGlobalObject("StackTest", new StackTestScriptingInterface(this)); + scriptEngine->registerGlobalObject("StackTest", new StackTestScriptingInterface(this)); #endif - globalObject().setProperty("KALILA", "isWaifu"); - globalObject().setProperty("Kute", newFunction([](QScriptContext* context, QScriptEngine* engine) -> QScriptValue { - return context->argument(0).toString().toLower() == "kalila" ? true : false; + scriptEngine->globalObject()->setProperty("KALILA", "isWaifu"); + scriptEngine->globalObject()->setProperty("Kute", scriptEngine->newFunction([](ScriptContext* context, ScriptEngine* engine) -> ScriptValuePointer { + return context->engine()->newValue(context->argument(0)->toString().toLower() == "kalila" ? true : false); })); } -void ScriptEngine::registerEnum(const QString& enumName, QMetaEnum newEnum) { - if (!newEnum.isValid()) { - qCCritical(scriptengine) << "registerEnum called on invalid enum with name " << enumName; - return; - } - - for (int i = 0; i < newEnum.keyCount(); i++) { - const char* keyName = newEnum.key(i); - QString fullName = enumName + "." + keyName; - registerValue(fullName, newEnum.keyToValue(keyName)); - } -} - -void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { - if (QThread::currentThread() != thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; -#endif - QMetaObject::invokeMethod(this, "registerValue", - Q_ARG(const QString&, valueName), - Q_ARG(QScriptValue, value)); - return; - } - - QStringList pathToValue = valueName.split("."); - int partsToGo = pathToValue.length(); - QScriptValue partObject = globalObject(); - - for (const auto& pathPart : pathToValue) { - partsToGo--; - if (!partObject.property(pathPart).isValid()) { - if (partsToGo > 0) { - //QObject *object = new QObject; - QScriptValue partValue = newArray(); //newQObject(object, QScriptEngine::ScriptOwnership); - partObject.setProperty(pathPart, partValue); - } else { - partObject.setProperty(pathPart, value); - } - } - partObject = partObject.property(pathPart); - } -} - -void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { - if (QThread::currentThread() != thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; -#endif - QMetaObject::invokeMethod(this, "registerGlobalObject", - Q_ARG(const QString&, name), - Q_ARG(QObject*, object)); - return; - } -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; -#endif - - if (!globalObject().property(name).isValid()) { - if (object) { - QScriptValue value = newQObject(object, QScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); - globalObject().setProperty(name, value); - } else { - globalObject().setProperty(name, QScriptValue()); - } - } -} - -void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { - if (QThread::currentThread() != thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; -#endif - QMetaObject::invokeMethod(this, "registerFunction", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), - Q_ARG(int, numArguments)); - return; - } -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; -#endif - - QScriptValue scriptFun = newFunction(functionSignature, numArguments); - globalObject().setProperty(name, scriptFun); -} - -void ScriptEngine::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { - if (QThread::currentThread() != thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; -#endif - QMetaObject::invokeMethod(this, "registerFunction", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), - Q_ARG(int, numArguments)); - return; - } -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; -#endif - - QScriptValue object = globalObject().property(parent); - if (object.isValid()) { - QScriptValue scriptFun = newFunction(functionSignature, numArguments); - object.setProperty(name, scriptFun); - } -} - -void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, - QScriptEngine::FunctionSignature setter, const QString& parent) { - if (QThread::currentThread() != thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - " name:" << name << "parent:" << parent; -#endif - QMetaObject::invokeMethod(this, "registerGetterSetter", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, getter), - Q_ARG(QScriptEngine::FunctionSignature, setter), - Q_ARG(const QString&, parent)); - return; - } -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; -#endif - - QScriptValue setterFunction = newFunction(setter, 1); - QScriptValue getterFunction = newFunction(getter); - - if (!parent.isNull() && !parent.isEmpty()) { - QScriptValue object = globalObject().property(parent); - if (object.isValid()) { - object.setProperty(name, setterFunction, QScriptValue::PropertySetter); - object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); - } - } else { - globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); - globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); - } -} - // Unregister the handlers for this eventName and entityID. -void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { +void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << " eventName:" << eventName; #endif QMetaObject::invokeMethod(this, "removeEventHandler", Q_ARG(const EntityItemID&, entityID), Q_ARG(const QString&, eventName), - Q_ARG(QScriptValue, handler)); + Q_ARG(ScriptValuePointer, handler)); return; } #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; + qCDebug(scriptengine) << "ScriptManager::removeEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; #endif if (!_registeredHandlers.contains(entityID)) { @@ -1054,30 +913,30 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin } RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID]; CallbackList& handlersForEvent = handlersOnEntity[eventName]; - // QScriptValue does not have operator==(), so we can't use QList::removeOne and friends. So iterate. + // ScriptValuePointer does not have operator==(), so we can't use QList::removeOne and friends. So iterate. for (int i = 0; i < handlersForEvent.count(); ++i) { - if (handlersForEvent[i].function.equals(handler)) { + if (handlersForEvent[i].function->equals(handler)) { handlersForEvent.removeAt(i); return; // Design choice: since comparison is relatively expensive, just remove the first matching handler. } } } // Register the handler. -void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { +void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << " eventName:" << eventName; #endif QMetaObject::invokeMethod(this, "addEventHandler", Q_ARG(const EntityItemID&, entityID), Q_ARG(const QString&, eventName), - Q_ARG(QScriptValue, handler)); + Q_ARG(ScriptValuePointer, handler)); return; } #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; + qCDebug(scriptengine) << "ScriptManager::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; #endif if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script... @@ -1105,7 +964,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& using SingleEntityHandler = std::function; auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler { return [this, eventName](const EntityItemID& entityItemID) { - forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(_engine.data()) }); }; }; @@ -1119,7 +978,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& auto makePointerHandler = [this](QString eventName) -> PointerHandler { return [this, eventName](const EntityItemID& entityItemID, const PointerEvent& event) { if (!EntityTree::areEntityClicksCaptured()) { - forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(_engine.data()), event.toScriptValue(_engine.data()) }); } }; }; @@ -1134,8 +993,8 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& using CollisionHandler = std::function; auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), - collisionToScriptValue(this, collision) }); + forwardHandlerCall(idA, eventName, { idA.toScriptValue(_engine.data()), idB.toScriptValue(_engine.data()), + collisionToScriptValue(_engine.data(), collision) }); }; }; @@ -1200,59 +1059,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler(). } -// this is not redundant -- the version in BaseScriptEngine is specifically not Q_INVOKABLE -QScriptValue ScriptEngine::evaluateInClosure(const QScriptValue& closure, const QScriptProgram& program) { - return BaseScriptEngine::evaluateInClosure(closure, program); -} - -QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) { - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { - return QScriptValue(); // bail early - } - - if (QThread::currentThread() != thread()) { - QScriptValue result; -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; -#endif - BLOCKING_INVOKE_METHOD(this, "evaluate", - Q_RETURN_ARG(QScriptValue, result), - Q_ARG(const QString&, sourceCode), - Q_ARG(const QString&, fileName), - Q_ARG(int, lineNumber)); - return result; - } - - // Check syntax - auto syntaxError = lintScript(sourceCode, fileName); - if (syntaxError.isError()) { - if (!isEvaluating()) { - syntaxError.setProperty("detail", "evaluate"); - } - raiseException(syntaxError); - maybeEmitUncaughtException("lint"); - return syntaxError; - } - QScriptProgram program { sourceCode, fileName, lineNumber }; - if (program.isNull()) { - // can this happen? - auto err = makeError("could not create QScriptProgram for " + fileName); - raiseException(err); - maybeEmitUncaughtException("compile"); - return err; - } - - QScriptValue result; - { - result = BaseScriptEngine::evaluate(program); - maybeEmitUncaughtException("evaluate"); - } - return result; -} - -void ScriptEngine::run() { +void ScriptManager::run() { if (QThread::currentThread() != qApp->thread() && _context == Context::CLIENT_SCRIPT) { // Flag that we're allowed to access local HTML files on UI created from C++ calls on this thread // (because we're a client script) @@ -1279,8 +1086,8 @@ void ScriptEngine::run() { { PROFILE_RANGE(script, _fileNameString); - evaluate(_scriptContents, _fileNameString); - maybeEmitUncaughtException(__FUNCTION__); + _engine->evaluate(_scriptContents, _fileNameString); + _engine->maybeEmitUncaughtException(__FUNCTION__); } #ifdef _WIN32 // VS13 does not sleep_until unless it uses the system_clock, see: @@ -1300,7 +1107,7 @@ void ScriptEngine::run() { std::chrono::microseconds totalUpdates(0); - // TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine + // TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptManager while (!_isFinished) { auto beforeSleep = clock::now(); @@ -1406,11 +1213,11 @@ void ScriptEngine::run() { _lastUpdate = now; // only clear exceptions if we are not in the middle of evaluating - if (!isEvaluating() && hasUncaughtException()) { + if (!_engine->isEvaluating() && _engine->hasUncaughtException()) { qCWarning(scriptengine) << __FUNCTION__ << "---------- UNCAUGHT EXCEPTION --------"; - qCWarning(scriptengine) << "runInThread" << uncaughtException().toString(); - emit unhandledException(cloneUncaughtException(__FUNCTION__)); - clearExceptions(); + qCWarning(scriptengine) << "runInThread" << _engine->uncaughtException()->toString(); + emit unhandledException(_engine->cloneUncaughtException(__FUNCTION__)); + _engine->clearExceptions(); } } scriptInfoMessage("Script Engine stopping:" + getFilename()); @@ -1434,7 +1241,7 @@ void ScriptEngine::run() { } } - emit finished(_fileNameString, qSharedPointerCast(sharedFromThis())); + emit finished(_fileNameString, qSharedPointerCast(sharedFromThis())); // Don't leave our local-file-access flag laying around, reset it to false when the scriptengine // thread is finished @@ -1446,7 +1253,7 @@ void ScriptEngine::run() { // NOTE: This is private because it must be called on the same thread that created the timers, which is why // we want to only call it in our own run "shutdown" processing. -void ScriptEngine::stopAllTimers() { +void ScriptManager::stopAllTimers() { QMutableHashIterator i(_timerFunctionMap); int j {0}; while (i.hasNext()) { @@ -1457,7 +1264,7 @@ void ScriptEngine::stopAllTimers() { } } -void ScriptEngine::stopAllTimersForEntityScript(const EntityItemID& entityID) { +void ScriptManager::stopAllTimersForEntityScript(const EntityItemID& entityID) { // We could maintain a separate map of entityID => QTimer, but someone will have to prove to me that it's worth the complexity. -HRS QVector toDelete; QMutableHashIterator i(_timerFunctionMap); @@ -1475,7 +1282,7 @@ void ScriptEngine::stopAllTimersForEntityScript(const EntityItemID& entityID) { } -void ScriptEngine::stop(bool marshal) { +void ScriptManager::stop(bool marshal) { _isStopping = true; // this can be done on any thread if (marshal) { @@ -1489,34 +1296,34 @@ void ScriptEngine::stop(bool marshal) { } // Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread. -void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) { +void ScriptManager::callAnimationStateHandler(ScriptValuePointer callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; #endif QMetaObject::invokeMethod(this, "callAnimationStateHandler", - Q_ARG(QScriptValue, callback), + Q_ARG(ScriptValuePointer, callback), Q_ARG(AnimVariantMap, parameters), Q_ARG(QStringList, names), Q_ARG(bool, useNames), Q_ARG(AnimVariantResultHandler, resultHandler)); return; } - QScriptValue javascriptParameters = parameters.animVariantMapToScriptValue(this, names, useNames); - QScriptValueList callingArguments; + ScriptValuePointer javascriptParameters = parameters.animVariantMapToScriptValue(_engine.get(), names, useNames); + ScriptValueList callingArguments; callingArguments << javascriptParameters; assert(currentEntityIdentifier.isInvalidID()); // No animation state handlers from entity scripts. - QScriptValue result = callback.call(QScriptValue(), callingArguments); + ScriptValuePointer result = callback->call(ScriptValuePointer(), callingArguments); // validate result from callback function. - if (result.isValid() && result.isObject()) { + if (result->isValid() && result->isObject()) { resultHandler(result); } else { - qCWarning(scriptengine) << "ScriptEngine::callAnimationStateHandler invalid return argument from callback, expected an object"; + qCWarning(scriptengine) << "ScriptManager::callAnimationStateHandler invalid return argument from callback, expected an object"; } } -void ScriptEngine::updateMemoryCost(const qint64& deltaSize) { +void ScriptManager::updateMemoryCost(const qint64& deltaSize) { if (deltaSize > 0) { // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. #if defined(Q_OS_WIN) || defined(Q_OS_MAC) @@ -1525,7 +1332,7 @@ void ScriptEngine::updateMemoryCost(const qint64& deltaSize) { } } -void ScriptEngine::timerFired() { +void ScriptManager::timerFired() { { QSharedPointer scriptEngines(_scriptEngines); if (!scriptEngines || scriptEngines->isStopped()) { @@ -1544,19 +1351,19 @@ void ScriptEngine::timerFired() { } // call the associated JS function, if it exists - if (timerData.function.isValid()) { + if (timerData.function->isValid()) { PROFILE_RANGE(script, __FUNCTION__); auto preTimer = p_high_resolution_clock::now(); - callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, QScriptValueList()); + callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, ScriptValueList()); auto postTimer = p_high_resolution_clock::now(); auto elapsed = (postTimer - preTimer); _totalTimerExecution += std::chrono::duration_cast(elapsed); } else { - qCWarning(scriptengine) << "timerFired -- invalid function" << timerData.function.toVariant().toString(); + qCWarning(scriptengine) << "timerFired -- invalid function" << timerData.function->toVariant().toString(); } } -QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { +QObject* ScriptManager::setupTimerWithInterval(const ScriptValuePointer& function, int intervalMS, bool isSingleShot) { // create the timer, add it to the map, and start it QTimer* newTimer = new QTimer(this); newTimer->setSingleShot(isSingleShot); @@ -1567,10 +1374,10 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int newTimer->setTimerType(Qt::PreciseTimer); } - connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); + connect(newTimer, &QTimer::timeout, this, &ScriptManager::timerFired); // make sure the timer stops when the script does - connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); + connect(this, &ScriptManager::scriptEnding, newTimer, &QTimer::stop); CallbackData timerData = { function, currentEntityIdentifier, currentSandboxURL }; @@ -1580,7 +1387,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int return newTimer; } -QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) { +QObject* ScriptManager::setInterval(const ScriptValuePointer& function, int intervalMS) { QSharedPointer scriptEngines(_scriptEngines); if (!scriptEngines || scriptEngines->isStopped()) { scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename()); @@ -1590,7 +1397,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) return setupTimerWithInterval(function, intervalMS, false); } -QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { +QObject* ScriptManager::setTimeout(const ScriptValuePointer& function, int timeoutMS) { QSharedPointer scriptEngines(_scriptEngines); if (!scriptEngines || scriptEngines->isStopped()) { scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename()); @@ -1600,7 +1407,7 @@ QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { return setupTimerWithInterval(function, timeoutMS, true); } -void ScriptEngine::stopTimer(QTimer *timer) { +void ScriptManager::stopTimer(QTimer *timer) { if (_timerFunctionMap.contains(timer)) { timer->stop(); _timerFunctionMap.remove(timer); @@ -1610,7 +1417,7 @@ void ScriptEngine::stopTimer(QTimer *timer) { } } -QUrl ScriptEngine::resolvePath(const QString& include) const { +QUrl ScriptManager::resolvePath(const QString& include) const { QUrl url(include); // first lets check to see if it's already a full URL -- or a Windows path like "c:/" if (include.startsWith("/") || url.scheme().length() == 1) { @@ -1623,10 +1430,10 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { // we apparently weren't a fully qualified url, so, let's assume we're relative // to the first absolute URL in the JS scope chain QUrl parentURL; - auto context = currentContext(); + auto context = _engine->currentContext(); do { - QScriptContextInfo contextInfo { context }; - parentURL = QUrl(contextInfo.fileName()); + auto contextInfo = context->functionContext(); + parentURL = QUrl(contextInfo->fileName()); context = context->parentContext(); } while (parentURL.isRelative() && context); @@ -1650,26 +1457,26 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { return url; } -QUrl ScriptEngine::resourcesPath() const { +QUrl ScriptManager::resourcesPath() const { return QUrl(PathUtils::resourcesUrl()); } -void ScriptEngine::print(const QString& message) { +void ScriptManager::print(const QString& message) { emit printedMessage(message, getFilename()); } -void ScriptEngine::beginProfileRange(const QString& label) const { +void ScriptManager::beginProfileRange(const QString& label) const { PROFILE_SYNC_BEGIN(script, label.toStdString().c_str(), label.toStdString().c_str()); } -void ScriptEngine::endProfileRange(const QString& label) const { +void ScriptManager::endProfileRange(const QString& label) const { PROFILE_SYNC_END(script, label.toStdString().c_str(), label.toStdString().c_str()); } // Script.require.resolve -- like resolvePath, but performs more validation and throws exceptions on invalid module identifiers (for consistency with Node.js) -QString ScriptEngine::_requireResolve(const QString& moduleId, const QString& relativeTo) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { +QString ScriptManager::_requireResolve(const QString& moduleId, const QString& relativeTo) { + if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return QString(); } QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); @@ -1681,9 +1488,9 @@ QString ScriptEngine::_requireResolve(const QString& moduleId, const QString& re } auto message = QString("Cannot find module '%1' (%2)").arg(displayId); - auto throwResolveError = [&](const QScriptValue& error) -> QString { - raiseException(error); - maybeEmitUncaughtException("require.resolve"); + auto throwResolveError = [&](const ScriptValuePointer& error) -> QString { + _engine->raiseException(error); + _engine->maybeEmitUncaughtException("require.resolve"); return QString(); }; @@ -1692,11 +1499,11 @@ QString ScriptEngine::_requireResolve(const QString& moduleId, const QString& re if (idLength < 1 || idLength > MAX_MODULE_ID_LENGTH) { auto details = QString("rejecting invalid module id size (%1 chars [1,%2])") .arg(idLength).arg(MAX_MODULE_ID_LENGTH); - return throwResolveError(makeError(message.arg(details), "RangeError")); + return throwResolveError(_engine->makeError(_engine->newValue(message.arg(details)), "RangeError")); } // this regex matches: absolute, dotted or path-like URLs - // (ie: the kind of stuff ScriptEngine::resolvePath already handles) + // (ie: the kind of stuff ScriptManager::resolvePath already handles) QRegularExpression qualified ("^\\w+:|^/|^[.]{1,2}(/|$)"); // this is for module.require (which is a bound version of require that's always relative to the module path) @@ -1719,15 +1526,15 @@ QString ScriptEngine::_requireResolve(const QString& moduleId, const QString& re if (QFileInfo(unanchoredUrl.toLocalFile()).isFile()) { auto msg = QString("relative module ids must be anchored; use './%1' instead") .arg(moduleId); - return throwResolveError(makeError(message.arg(msg))); + return throwResolveError(_engine->makeError(_engine->newValue(message.arg(msg)))); } } - return throwResolveError(makeError(message.arg("system module not found"))); + return throwResolveError(_engine->makeError(_engine->newValue(message.arg("system module not found")))); } } if (url.isRelative()) { - return throwResolveError(makeError(message.arg("could not resolve module id"))); + return throwResolveError(_engine->makeError(_engine->newValue(message.arg("could not resolve module id")))); } // if it looks like a local file, verify that it's an allowed path and really a file @@ -1740,98 +1547,98 @@ QString ScriptEngine::_requireResolve(const QString& moduleId, const QString& re bool disallowOutsideFiles = !PathUtils::defaultScriptsLocation().isParentOf(canonical) && !currentSandboxURL.isLocalFile(); if (disallowOutsideFiles && !PathUtils::isDescendantOf(canonical, currentSandboxURL)) { - return throwResolveError(makeError(message.arg( + return throwResolveError(_engine->makeError(_engine->newValue(message.arg( QString("path '%1' outside of origin script '%2' '%3'") .arg(PathUtils::stripFilename(url)) .arg(PathUtils::stripFilename(currentSandboxURL)) .arg(canonical.toString()) - ))); + )))); } if (!file.exists()) { - return throwResolveError(makeError(message.arg("path does not exist: " + url.toLocalFile()))); + return throwResolveError(_engine->makeError(_engine->newValue(message.arg("path does not exist: " + url.toLocalFile())))); } if (!file.isFile()) { - return throwResolveError(makeError(message.arg("path is not a file: " + url.toLocalFile()))); + return throwResolveError(_engine->makeError(_engine->newValue(message.arg("path is not a file: " + url.toLocalFile())))); } } - maybeEmitUncaughtException(__FUNCTION__); + _engine->maybeEmitUncaughtException(__FUNCTION__); return url.toString(); } // retrieves the current parent module from the JS scope chain -QScriptValue ScriptEngine::currentModule() { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return unboundNullValue(); +ScriptValuePointer ScriptManager::currentModule() { + if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { + return _engine->nullValue(); } - auto jsRequire = globalObject().property("Script").property("require"); - auto cache = jsRequire.property("cache"); - auto candidate = QScriptValue(); - for (auto c = currentContext(); c && !candidate.isObject(); c = c->parentContext()) { - QScriptContextInfo contextInfo { c }; - candidate = cache.property(contextInfo.fileName()); + auto jsRequire = _engine->globalObject()->property("Script")->property("require"); + auto cache = jsRequire->property("cache"); + auto candidate = ScriptValuePointer(); + for (auto c = _engine->currentContext(); c && !candidate->isObject(); c = c->parentContext()) { + auto contextInfo = c->functionContext(); + candidate = cache->property(contextInfo->fileName()); } - if (!candidate.isObject()) { - return QScriptValue(); + if (!candidate->isObject()) { + return ScriptValuePointer(); } return candidate; } // replaces or adds "module" to "parent.children[]" array // (for consistency with Node.js and userscript cache invalidation without "cache busters") -bool ScriptEngine::registerModuleWithParent(const QScriptValue& module, const QScriptValue& parent) { - auto children = parent.property("children"); - if (children.isArray()) { - auto key = module.property("id"); - auto length = children.property("length").toInt32(); +bool ScriptManager::registerModuleWithParent(const ScriptValuePointer& module, const ScriptValuePointer& parent) { + auto children = parent->property("children"); + if (children->isArray()) { + auto key = module->property("id"); + auto length = children->property("length")->toInt32(); for (int i = 0; i < length; i++) { - if (children.property(i).property("id").strictlyEquals(key)) { - qCDebug(scriptengine_module) << key.toString() << " updating parent.children[" << i << "] = module"; - children.setProperty(i, module); + if (children->property(i)->property("id")->strictlyEquals(key)) { + qCDebug(scriptengine_module) << key->toString() << " updating parent.children[" << i << "] = module"; + children->setProperty(i, module); return true; } } - qCDebug(scriptengine_module) << key.toString() << " appending parent.children[" << length << "] = module"; - children.setProperty(length, module); + qCDebug(scriptengine_module) << key->toString() << " appending parent.children[" << length << "] = module"; + children->setProperty(length, module); return true; - } else if (parent.isValid()) { - qCDebug(scriptengine_module) << "registerModuleWithParent -- unrecognized parent" << parent.toVariant().toString(); + } else if (parent->isValid()) { + qCDebug(scriptengine_module) << "registerModuleWithParent -- unrecognized parent" << parent->toVariant().toString(); } return false; } // creates a new JS "module" Object with default metadata properties -QScriptValue ScriptEngine::newModule(const QString& modulePath, const QScriptValue& parent) { - auto closure = newObject(); - auto exports = newObject(); - auto module = newObject(); - qCDebug(scriptengine_module) << "newModule" << parent.property("filename").toString(); +ScriptValuePointer ScriptManager::newModule(const QString& modulePath, const ScriptValuePointer& parent) { + auto closure = _engine->newObject(); + auto exports = _engine->newObject(); + auto module = _engine->newObject(); + qCDebug(scriptengine_module) << "newModule" << parent->property("filename")->toString(); - closure.setProperty("module", module, READONLY_PROP_FLAGS); + closure->setProperty("module", module, READONLY_PROP_FLAGS); // note: this becomes the "exports" free variable, so should not be set read only - closure.setProperty("exports", exports); + closure->setProperty("exports", exports); // make the closure available to module instantiation - module.setProperty("__closure__", closure, READONLY_HIDDEN_PROP_FLAGS); + module->setProperty("__closure__", closure, READONLY_HIDDEN_PROP_FLAGS); // for consistency with Node.js Module - module.setProperty("id", modulePath, READONLY_PROP_FLAGS); - module.setProperty("filename", modulePath, READONLY_PROP_FLAGS); - module.setProperty("exports", exports); // not readonly - module.setProperty("loaded", false, READONLY_PROP_FLAGS); - module.setProperty("parent", parent, READONLY_PROP_FLAGS); - module.setProperty("children", newArray(), READONLY_PROP_FLAGS); + module->setProperty("id", modulePath, READONLY_PROP_FLAGS); + module->setProperty("filename", modulePath, READONLY_PROP_FLAGS); + module->setProperty("exports", exports); // not readonly + module->setProperty("loaded", false, READONLY_PROP_FLAGS); + module->setProperty("parent", parent, READONLY_PROP_FLAGS); + module->setProperty("children", _engine->newArray(), READONLY_PROP_FLAGS); // module.require is a bound version of require that always resolves relative to that module's path - auto boundRequire = QScriptEngine::evaluate("(function(id) { return Script.require(Script.require.resolve(id, this.filename)); })", "(boundRequire)"); - module.setProperty("require", boundRequire, READONLY_PROP_FLAGS); + auto boundRequire = _engine->evaluate("(function(id) { return Script.require(Script.require.resolve(id, this.filename)); })", "(boundRequire)"); + module->setProperty("require", boundRequire, READONLY_PROP_FLAGS); return module; } // synchronously fetch a module's source code using BatchLoader -QVariantMap ScriptEngine::fetchModuleSource(const QString& modulePath, const bool forceDownload) { +QVariantMap ScriptManager::fetchModuleSource(const QString& modulePath, const bool forceDownload) { using UrlMap = QMap; auto scriptCache = DependencyManager::get(); QVariantMap req; @@ -1889,63 +1696,63 @@ QVariantMap ScriptEngine::fetchModuleSource(const QString& modulePath, const boo } // evaluate a pending module object using the fetched source code -QScriptValue ScriptEngine::instantiateModule(const QScriptValue& module, const QString& sourceCode) { - QScriptValue result; - auto modulePath = module.property("filename").toString(); - auto closure = module.property("__closure__"); +ScriptValuePointer ScriptManager::instantiateModule(const ScriptValuePointer& module, const QString& sourceCode) { + ScriptValuePointer result; + auto modulePath = module->property("filename")->toString(); + auto closure = module->property("__closure__"); qCDebug(scriptengine_module) << QString("require.instantiateModule: %1 / %2 bytes") .arg(QUrl(modulePath).fileName()).arg(sourceCode.length()); - if (module.property("content-type").toString() == "application/json") { + if (module->property("content-type")->toString() == "application/json") { qCDebug(scriptengine_module) << "... parsing as JSON"; - closure.setProperty("__json", sourceCode); - result = evaluateInClosure(closure, { "module.exports = JSON.parse(__json)", modulePath }); + closure->setProperty("__json", sourceCode); + result = _engine->evaluateInClosure(closure, _engine->newProgram( "module.exports = JSON.parse(__json)", modulePath )); } else { // scoped vars for consistency with Node.js - closure.setProperty("require", module.property("require")); - closure.setProperty("__filename", modulePath, READONLY_HIDDEN_PROP_FLAGS); - closure.setProperty("__dirname", QString(modulePath).replace(QRegExp("/[^/]*$"), ""), READONLY_HIDDEN_PROP_FLAGS); - result = evaluateInClosure(closure, { sourceCode, modulePath }); + closure->setProperty("require", module->property("require")); + closure->setProperty("__filename", modulePath, READONLY_HIDDEN_PROP_FLAGS); + closure->setProperty("__dirname", QString(modulePath).replace(QRegExp("/[^/]*$"), ""), READONLY_HIDDEN_PROP_FLAGS); + result = _engine->evaluateInClosure(closure, _engine->newProgram( sourceCode, modulePath )); } - maybeEmitUncaughtException(__FUNCTION__); + _engine->maybeEmitUncaughtException(__FUNCTION__); return result; } // CommonJS/Node.js like require/module support -QScriptValue ScriptEngine::require(const QString& moduleId) { - qCDebug(scriptengine_module) << "ScriptEngine::require(" << moduleId.left(MAX_DEBUG_VALUE_LENGTH) << ")"; - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return unboundNullValue(); +ScriptValuePointer ScriptManager::require(const QString& moduleId) { + qCDebug(scriptengine_module) << "ScriptManager::require(" << moduleId.left(MAX_DEBUG_VALUE_LENGTH) << ")"; + if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { + return _engine->nullValue(); } - auto jsRequire = globalObject().property("Script").property("require"); + auto jsRequire = _engine->globalObject()->property("Script")->property("require"); auto cacheMeta = jsRequire.data(); - auto cache = jsRequire.property("cache"); + auto cache = jsRequire->property("cache"); auto parent = currentModule(); - auto throwModuleError = [&](const QString& modulePath, const QScriptValue& error) { - cache.setProperty(modulePath, nullValue()); + auto throwModuleError = [&](const QString& modulePath, const ScriptValuePointer& error) { + cache->setProperty(modulePath, _engine->nullValue()); if (!error.isNull()) { #ifdef DEBUG_JS_MODULES qCWarning(scriptengine_module) << "throwing module error:" << error.toString() << modulePath << error.property("stack").toString(); #endif - raiseException(error); + _engine->raiseException(error); } - maybeEmitUncaughtException("module"); - return unboundNullValue(); + _engine->maybeEmitUncaughtException("module"); + return _engine->nullValue(); }; // start by resolving the moduleId into a fully-qualified path/URL QString modulePath = _requireResolve(moduleId); - if (modulePath.isNull() || hasUncaughtException()) { + if (modulePath.isNull() || _engine->hasUncaughtException()) { // the resolver already threw an exception -- bail early - maybeEmitUncaughtException(__FUNCTION__); - return unboundNullValue(); + _engine->maybeEmitUncaughtException(__FUNCTION__); + return _engine->nullValue(); } // check the resolved path against the cache - auto module = cache.property(modulePath); + auto module = cache->property(modulePath); // modules get cached in `Script.require.cache` and (similar to Node.js) users can access it // to inspect particular entries and invalidate them by deleting the key: @@ -1955,18 +1762,18 @@ QScriptValue ScriptEngine::require(const QString& moduleId) { Setting::Handle getCachebustSetting {"cachebustScriptRequire", false }; // cacheMeta is just used right now to tell deleted keys apart from undefined ones - bool invalidateCache = getCachebustSetting.get() || (module.isUndefined() && cacheMeta.property(moduleId).isValid()); + bool invalidateCache = getCachebustSetting.get() || (module->isUndefined() && cacheMeta->property(moduleId)->isValid()); // reset the cacheMeta record so invalidation won't apply next time, even if the module fails to load - cacheMeta.setProperty(modulePath, QScriptValue()); + cacheMeta->setProperty(modulePath, ScriptValuePointer()); - auto exports = module.property("exports"); - if (!invalidateCache && exports.isObject()) { + auto exports = module->property("exports"); + if (!invalidateCache && exports->isObject()) { // we have found a cached module -- just need to possibly register it with current parent qCDebug(scriptengine_module) << QString("require - using cached module for '%1' (loaded: %2)") - .arg(moduleId).arg(module.property("loaded").toString()); + .arg(moduleId).arg(module->property("loaded")->toString()); registerModuleWithParent(module, parent); - maybeEmitUncaughtException("cached module"); + _engine->maybeEmitUncaughtException("cached module"); return exports; } @@ -1975,14 +1782,14 @@ QScriptValue ScriptEngine::require(const QString& moduleId) { registerModuleWithParent(module, parent); // add it to the cache (this is done early so any cyclic dependencies pick up) - cache.setProperty(modulePath, module); + cache->setProperty(modulePath, module); // download the module source auto req = fetchModuleSource(modulePath, invalidateCache); if (!req.contains("success") || !req["success"].toBool()) { auto error = QString("error retrieving script (%1)").arg(req["status"].toString()); - return throwModuleError(modulePath, error); + return throwModuleError(modulePath, _engine->newValue(error)); } #if DEBUG_JS_MODULES @@ -1993,37 +1800,37 @@ QScriptValue ScriptEngine::require(const QString& moduleId) { auto sourceCode = req["contents"].toString(); if (QUrl(modulePath).fileName().endsWith(".json", Qt::CaseInsensitive)) { - module.setProperty("content-type", "application/json"); + module->setProperty("content-type", "application/json"); } else { - module.setProperty("content-type", "application/javascript"); + module->setProperty("content-type", "application/javascript"); } // evaluate the module auto result = instantiateModule(module, sourceCode); - if (result.isError() && !result.strictlyEquals(module.property("exports"))) { - qCWarning(scriptengine_module) << "-- result.isError --" << result.toString(); + if (result->isError() && !result->strictlyEquals(module->property("exports"))) { + qCWarning(scriptengine_module) << "-- result.isError --" << result->toString(); return throwModuleError(modulePath, result); } // mark as fully-loaded - module.setProperty("loaded", true, READONLY_PROP_FLAGS); + module->setProperty("loaded", true, READONLY_PROP_FLAGS); // set up a new reference point for detecting cache key deletion - cacheMeta.setProperty(modulePath, module); + cacheMeta->setProperty(modulePath, module); - qCDebug(scriptengine_module) << "//ScriptEngine::require(" << moduleId << ")"; + qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")"; - maybeEmitUncaughtException(__FUNCTION__); - return module.property("exports"); + _engine->maybeEmitUncaughtException(__FUNCTION__); + return module->property("exports"); } // If a callback is specified, the included files will be loaded asynchronously and the callback will be called // when all of the files have finished loading. // If no callback is specified, the included files will be loaded synchronously and will block execution until // all of the files have finished loading. -void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { +void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer callback) { + if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return; } QSharedPointer scriptEngines(_scriptEngines); @@ -2084,13 +1891,13 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac // to this script's url during its initial evaluation _parentURL = url.toString(); auto operation = [&]() { - evaluate(contents, url.toString()); + _engine->evaluate(contents, url.toString()); }; doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation); - if (hasUncaughtException()) { - emit unhandledException(cloneUncaughtException("evaluateInclude")); - clearExceptions(); + if(_engine->hasUncaughtException()) { + emit unhandledException(_engine->cloneUncaughtException("evaluateInclude")); + _engine->clearExceptions(); } } else { scriptPrintedMessage("Script.include() skipping evaluation of previously included url:" + url.toString()); @@ -2099,8 +1906,8 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac } _parentURL = parentURL; - if (callback.isFunction()) { - callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, QScriptValue(callback), QScriptValue(), QScriptValueList()); + if (callback->isFunction()) { + callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, ScriptValuePointer(callback), ScriptValuePointer(), ScriptValueList()); } loader->deleteLater(); @@ -2113,14 +1920,14 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac loader->start(processLevelMaxRetries); - if (!callback.isFunction() && !loader->isFinished()) { + if (!callback->isFunction() && !loader->isFinished()) { QEventLoop loop; QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit); loop.exec(); } } -void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { +void ScriptManager::include(const QString& includeFile, ScriptValuePointer callback) { QSharedPointer scriptEngines(_scriptEngines); if (!scriptEngines || scriptEngines->isStopped()) { scriptWarningMessage("Script.include() while shutting down is ignored... includeFile:" @@ -2134,10 +1941,10 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { } // NOTE: The load() command is similar to the include() command except that it loads the script -// as a stand-alone script. To accomplish this, the ScriptEngine class just emits a signal which +// as a stand-alone script. To accomplish this, the ScriptManager class just emits a signal which // the Application or other context will connect to in order to know to actually load the script -void ScriptEngine::load(const QString& loadFile) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { +void ScriptManager::load(const QString& loadFile) { + if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return; } QSharedPointer scriptEngines(_scriptEngines); @@ -2163,9 +1970,9 @@ void ScriptEngine::load(const QString& loadFile) { } // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args -void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHandlerArgs) { +void ScriptManager::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, ScriptValueList eventHandlerArgs) { if (QThread::currentThread() != thread()) { - qCDebug(scriptengine) << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; + qCDebug(scriptengine) << "*** ERROR *** ScriptManager::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; assert(false); return ; } @@ -2183,12 +1990,12 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin // and the entity scripts may be for entities other than the one this is a handler for. // Fortunately, the definingEntityIdentifier captured the entity script id (if any) when the handler was added. CallbackData& handler = handlersForEvent[i]; - callWithEnvironment(handler.definingEntityIdentifier, handler.definingSandboxURL, handler.function, QScriptValue(), eventHandlerArgs); + callWithEnvironment(handler.definingEntityIdentifier, handler.definingSandboxURL, handler.function, ScriptValuePointer(), eventHandlerArgs); } } } -int ScriptEngine::getNumRunningEntityScripts() const { +int ScriptManager::getNumRunningEntityScripts() const { QReadLocker locker { &_entityScriptsLock }; int sum = 0; for (const auto& st : _entityScripts) { @@ -2199,7 +2006,7 @@ int ScriptEngine::getNumRunningEntityScripts() const { return sum; } -void ScriptEngine::setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details) { +void ScriptManager::setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details) { { QWriteLocker locker { &_entityScriptsLock }; _entityScripts[entityID] = details; @@ -2207,7 +2014,7 @@ void ScriptEngine::setEntityScriptDetails(const EntityItemID& entityID, const En emit entityScriptDetailsUpdated(); } -void ScriptEngine::updateEntityScriptStatus(const EntityItemID& entityID, const EntityScriptStatus &status, const QString& errorInfo) { +void ScriptManager::updateEntityScriptStatus(const EntityItemID& entityID, const EntityScriptStatus &status, const QString& errorInfo) { { QWriteLocker locker { &_entityScriptsLock }; EntityScriptDetails& details = _entityScripts[entityID]; @@ -2217,7 +2024,7 @@ void ScriptEngine::updateEntityScriptStatus(const EntityItemID& entityID, const emit entityScriptDetailsUpdated(); } -QVariant ScriptEngine::cloneEntityScriptDetails(const EntityItemID& entityID) { +QVariant ScriptManager::cloneEntityScriptDetails(const EntityItemID& entityID) { static const QVariant NULL_VARIANT { qVariantFromValue((QObject*)nullptr) }; QVariantMap map; if (entityID.isNull()) { @@ -2259,11 +2066,11 @@ QVariant ScriptEngine::cloneEntityScriptDetails(const EntityItemID& entityID) { return map; } -QFuture ScriptEngine::getLocalEntityScriptDetails(const EntityItemID& entityID) { - return QtConcurrent::run(this, &ScriptEngine::cloneEntityScriptDetails, entityID); +QFuture ScriptManager::getLocalEntityScriptDetails(const EntityItemID& entityID) { + return QtConcurrent::run(this, &ScriptManager::cloneEntityScriptDetails, entityID); } -bool ScriptEngine::getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const { +bool ScriptManager::getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const { QReadLocker locker { &_entityScriptsLock }; auto it = _entityScripts.constFind(entityID); if (it == _entityScripts.constEnd()) { @@ -2273,12 +2080,12 @@ bool ScriptEngine::getEntityScriptDetails(const EntityItemID& entityID, EntitySc return true; } -bool ScriptEngine::hasEntityScriptDetails(const EntityItemID& entityID) const { +bool ScriptManager::hasEntityScriptDetails(const EntityItemID& entityID) const { QReadLocker locker { &_entityScriptsLock }; return _entityScripts.contains(entityID); } -void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) { +void ScriptManager::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "loadEntityScript", Q_ARG(const EntityItemID&, entityID), @@ -2320,12 +2127,12 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& auto scriptCache = DependencyManager::get(); // note: see EntityTreeRenderer.cpp for shared pointer lifecycle management - QWeakPointer weakRef(sharedFromThis()); + QWeakPointer weakRef(sharedFromThis()); scriptCache->getScriptContents(entityScript, [this, weakRef, entityScript, entityID](const QString& url, const QString& contents, bool isURL, bool success, const QString& status) { - QSharedPointer strongRef(weakRef); + QSharedPointer strongRef(weakRef); if (!strongRef) { - qCWarning(scriptengine) << "loadEntityScript.contentAvailable -- ScriptEngine was deleted during getScriptContents!!"; + qCWarning(scriptengine) << "loadEntityScript.contentAvailable -- ScriptManager was deleted during getScriptContents!!"; return; } if (isStopping()) { @@ -2378,10 +2185,10 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& // The JSDoc is for the callEntityScriptMethod() call in this method. // since all of these operations can be asynch we will always do the actual work in the response handler // for the download -void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success , const QString& status) { +void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success , const QString& status) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success; @@ -2398,7 +2205,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co } #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; + qCDebug(scriptengine) << "ScriptManager::entityScriptContentAvailable() thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif auto scriptCache = DependencyManager::get(); @@ -2429,21 +2236,21 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co } // SYNTAX ERRORS - auto syntaxError = lintScript(contents, fileName); - if (syntaxError.isError()) { - auto message = syntaxError.property("formatted").toString(); + auto syntaxError = _engine->lintScript(contents, fileName); + if (syntaxError->isError()) { + auto message = syntaxError->property("formatted")->toString(); if (message.isEmpty()) { - message = syntaxError.toString(); + message = syntaxError->toString(); } setError(QString("Bad syntax (%1)").arg(message), EntityScriptStatus::ERROR_RUNNING_SCRIPT); - syntaxError.setProperty("detail", entityID.toString()); + syntaxError->setProperty("detail", entityID.toString()); emit unhandledException(syntaxError); return; } - QScriptProgram program { contents, fileName }; + auto program = _engine->newProgram( contents, fileName ); if (program.isNull()) { setError("Bad program (isNull)", EntityScriptStatus::ERROR_RUNNING_SCRIPT); - emit unhandledException(makeError("program.isNull")); + emit unhandledException(_engine->makeError(_engine->newValue("program.isNull"))); return; // done processing script } @@ -2453,29 +2260,29 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co // SANITY/PERFORMANCE CHECK USING SANDBOX const int SANDBOX_TIMEOUT = 0.25 * MSECS_PER_SECOND; - BaseScriptEngine sandbox; - sandbox.setProcessEventsInterval(SANDBOX_TIMEOUT); - QScriptValue testConstructor, exception; + ScriptEnginePointer sandbox = newScriptEngine(); + sandbox->setProcessEventsInterval(SANDBOX_TIMEOUT); + ScriptValuePointer testConstructor, exception; if (atoi(getenv("UNSAFE_ENTITY_SCRIPTS") ? getenv("UNSAFE_ENTITY_SCRIPTS") : "0")) { QTimer timeout; timeout.setSingleShot(true); timeout.start(SANDBOX_TIMEOUT); connect(&timeout, &QTimer::timeout, [=, &sandbox]{ - qCDebug(scriptengine) << "ScriptEngine::entityScriptContentAvailable timeout"; + qCDebug(scriptengine) << "ScriptManager::entityScriptContentAvailable timeout"; // Guard against infinite loops and non-performant code - sandbox.raiseException( - sandbox.makeError(QString("Timed out (entity constructors are limited to %1ms)").arg(SANDBOX_TIMEOUT)) + sandbox->raiseException( + sandbox->makeError(sandbox->newValue(QString("Timed out (entity constructors are limited to %1ms)").arg(SANDBOX_TIMEOUT))) ); }); - testConstructor = sandbox.evaluate(program); + testConstructor = sandbox->evaluate(program); - if (sandbox.hasUncaughtException()) { - exception = sandbox.cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); - sandbox.clearExceptions(); - } else if (testConstructor.isError()) { + if (sandbox->hasUncaughtException()) { + exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); + sandbox->clearExceptions(); + } else if (testConstructor->isError()) { exception = testConstructor; } } else { @@ -2515,7 +2322,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co // END bypass whitelist based on current domain. // Start processing scripts through the whitelist. - if (ScriptEngine::getContext() == "entity_server") { // If running on the server, do not engage whitelist. + if (ScriptManager::getContext() == "entity_server") { // If running on the server, do not engage whitelist. passList = true; } else if (!passList) { // If waved through, do not engage whitelist. for (const auto& str : safeURLPrefixes) { @@ -2532,25 +2339,25 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co if (!passList) { // If the entity failed to pass for any reason, it's blocked and an error is thrown. qCDebug(scriptengine) << whitelistPrefix << "(disabled entity script)" << entityID.toString() << scriptOrURL; - exception = makeError("UNSAFE_ENTITY_SCRIPTS == 0"); + exception = _engine->makeError(_engine->newValue("UNSAFE_ENTITY_SCRIPTS == 0")); } else { QTimer timeout; timeout.setSingleShot(true); timeout.start(SANDBOX_TIMEOUT); connect(&timeout, &QTimer::timeout, [=, &sandbox] { - qCDebug(scriptengine) << "ScriptEngine::entityScriptContentAvailable timeout"; + qCDebug(scriptengine) << "ScriptManager::entityScriptContentAvailable timeout"; // Guard against infinite loops and non-performant code - sandbox.raiseException( - sandbox.makeError(QString("Timed out (entity constructors are limited to %1ms)").arg(SANDBOX_TIMEOUT))); + sandbox->raiseException( + sandbox->makeError(sandbox->newValue(QString("Timed out (entity constructors are limited to %1ms)").arg(SANDBOX_TIMEOUT)))); }); - testConstructor = sandbox.evaluate(program); + testConstructor = sandbox->evaluate(program); - if (sandbox.hasUncaughtException()) { - exception = sandbox.cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); - sandbox.clearExceptions(); - } else if (testConstructor.isError()) { + if (sandbox->hasUncaughtException()) { + exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); + sandbox->clearExceptions(); + } else if (testConstructor->isError()) { exception = testConstructor; } } @@ -2560,30 +2367,30 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co // exception = makeError("UNSAFE_ENTITY_SCRIPTS == 0"); } - if (exception.isError()) { + if (exception->isError()) { // create a local copy using makeError to decouple from the sandbox engine - exception = makeError(exception); + exception = _engine->makeError(exception); setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); emit unhandledException(exception); return; } // CONSTRUCTOR VIABILITY - if (!testConstructor.isFunction()) { - QString testConstructorType = QString(testConstructor.toVariant().typeName()); + if (!testConstructor->isFunction()) { + QString testConstructorType = QString(testConstructor->toVariant().typeName()); if (testConstructorType == "") { testConstructorType = "empty"; } - QString testConstructorValue = testConstructor.toString(); + QString testConstructorValue = testConstructor->toString(); if (testConstructorValue.size() > MAX_DEBUG_VALUE_LENGTH) { testConstructorValue = testConstructorValue.mid(0, MAX_DEBUG_VALUE_LENGTH) + "..."; } auto message = QString("failed to load entity script -- expected a function, got %1, %2") .arg(testConstructorType).arg(testConstructorValue); - auto err = makeError(message); - err.setProperty("fileName", scriptOrURL); - err.setProperty("detail", "(constructor " + entityID.toString() + ")"); + auto err = _engine->makeError(_engine->newValue(message)); + err->setProperty("fileName", scriptOrURL); + err->setProperty("detail", "(constructor " + entityID.toString() + ")"); setError("Could not find constructor (" + testConstructorType + ")", EntityScriptStatus::ERROR_RUNNING_SCRIPT); emit unhandledException(err); @@ -2598,21 +2405,21 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co } // THE ACTUAL EVALUATION AND CONSTRUCTION - QScriptValue entityScriptConstructor, entityScriptObject; + ScriptValuePointer entityScriptConstructor, entityScriptObject; QUrl sandboxURL = currentSandboxURL.isEmpty() ? scriptOrURL : currentSandboxURL; auto initialization = [&]{ - entityScriptConstructor = evaluate(contents, fileName); - entityScriptObject = entityScriptConstructor.construct(); + entityScriptConstructor = _engine->evaluate(contents, fileName); + entityScriptObject = entityScriptConstructor->construct(); - if (hasUncaughtException()) { - entityScriptObject = cloneUncaughtException("(construct " + entityID.toString() + ")"); - clearExceptions(); + if (_engine->hasUncaughtException()) { + entityScriptObject = _engine->cloneUncaughtException("(construct " + entityID.toString() + ")"); + _engine->clearExceptions(); } }; doWithEnvironment(entityID, sandboxURL, initialization); - if (entityScriptObject.isError()) { + if (entityScriptObject->isError()) { auto exception = entityScriptObject; setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); emit unhandledException(exception); @@ -2645,10 +2452,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co * @returns {Signal} */ // The JSDoc is for the callEntityScriptMethod() call in this method. -void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) { +void ScriptManager::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID; #endif @@ -2658,7 +2465,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR return; } #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "ScriptManager::unloadEntityScript() called on correct thread [" << thread() << "] " "entityID:" << entityID; #endif @@ -2694,15 +2501,15 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR } } -QList ScriptEngine::getListOfEntityScriptIDs() { +QList ScriptManager::getListOfEntityScriptIDs() { QReadLocker locker{ &_entityScriptsLock }; return _entityScripts.keys(); } -void ScriptEngine::unloadAllEntityScripts(bool blockingCall) { +void ScriptManager::unloadAllEntityScripts(bool blockingCall) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; #endif QMetaObject::invokeMethod(this, "unloadAllEntityScripts", @@ -2710,7 +2517,7 @@ void ScriptEngine::unloadAllEntityScripts(bool blockingCall) { return; } #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; + qCDebug(scriptengine) << "ScriptManager::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; #endif QList keys; @@ -2736,7 +2543,7 @@ void ScriptEngine::unloadAllEntityScripts(bool blockingCall) { #endif // DEBUG_ENGINE_STATE } -void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { +void ScriptManager::refreshFileScript(const EntityItemID& entityID) { if (!HIFI_AUTOREFRESH_FILE_SCRIPTS || !hasEntityScriptDetails(entityID)) { return; } @@ -2768,36 +2575,36 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { // Even if entityID is supplied as currentEntityIdentifier, this still documents the source // of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different // global values for different entity scripts). -void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation) { +void ScriptManager::doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation) { EntityItemID oldIdentifier = currentEntityIdentifier; QUrl oldSandboxURL = currentSandboxURL; currentEntityIdentifier = entityID; currentSandboxURL = sandboxURL; #if DEBUG_CURRENT_ENTITY - QScriptValue oldData = this->globalObject().property("debugEntityID"); + ScriptValuePointer oldData = this->globalObject().property("debugEntityID"); this->globalObject().setProperty("debugEntityID", entityID.toScriptValue(this)); // Make the entityID available to javascript as a global. operation(); this->globalObject().setProperty("debugEntityID", oldData); #else operation(); #endif - maybeEmitUncaughtException(!entityID.isNull() ? entityID.toString() : __FUNCTION__); + _engine->maybeEmitUncaughtException(!entityID.isNull() ? entityID.toString() : __FUNCTION__); currentEntityIdentifier = oldIdentifier; currentSandboxURL = oldSandboxURL; } -void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args) { +void ScriptManager::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, ScriptValuePointer function, ScriptValuePointer thisObject, ScriptValueList args) { auto operation = [&]() { - function.call(thisObject, args); + function->call(thisObject, args); }; doWithEnvironment(entityID, sandboxURL, operation); } -void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params, const QUuid& remoteCallerID) { +void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params, const QUuid& remoteCallerID) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << "methodName:" << methodName; #endif @@ -2809,7 +2616,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS return; } #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "ScriptManager::callEntityScriptMethod() called on correct thread [" << thread() << "] " "entityID:" << entityID << "methodName:" << methodName; #endif @@ -2822,7 +2629,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS QWriteLocker locker { &_entityScriptsLock }; details = _entityScripts[entityID]; } - QScriptValue entityScript = details.scriptObject; // previously loaded + ScriptValuePointer entityScript = details.scriptObject; // previously loaded // If this is a remote call, we need to check to see if the function is remotely callable // we do this by checking for the existance of the 'remotelyCallable' property on the @@ -2832,11 +2639,11 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS if (remoteCallerID == QUuid()) { callAllowed = true; } else { - if (entityScript.property("remotelyCallable").isArray()) { - auto callables = entityScript.property("remotelyCallable"); - auto callableCount = callables.property("length").toInteger(); + if (entityScript->property("remotelyCallable")->isArray()) { + auto callables = entityScript->property("remotelyCallable"); + auto callableCount = callables->property("length")->toInteger(); for (int i = 0; i < callableCount; i++) { - auto callable = callables.property(i).toString(); + auto callable = callables->property(i)->toString(); if (callable == methodName) { callAllowed = true; break; @@ -2848,23 +2655,25 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS } } - if (callAllowed && entityScript.property(methodName).isFunction()) { - QScriptValueList args; - args << entityID.toScriptValue(this); - args << qScriptValueFromSequence(this, params); + if (callAllowed && entityScript->property(methodName)->isFunction()) { + auto scriptEngine = engine().data(); + + ScriptValueList args; + args << entityID.toScriptValue(scriptEngine); + args << scriptValueFromSequence(scriptEngine, params); - QScriptValue oldData = this->globalObject().property("Script").property("remoteCallerID"); - this->globalObject().property("Script").setProperty("remoteCallerID", remoteCallerID.toString()); // Make the remoteCallerID available to javascript as a global. - callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); - this->globalObject().property("Script").setProperty("remoteCallerID", oldData); + ScriptValuePointer oldData = scriptEngine->globalObject()->property("Script")->property("remoteCallerID"); + scriptEngine->globalObject()->property("Script")->setProperty("remoteCallerID", remoteCallerID.toString()); // Make the remoteCallerID available to javascript as a global. + callWithEnvironment(entityID, details.definingSandboxURL, entityScript->property(methodName), entityScript, args); + scriptEngine->globalObject()->property("Script")->setProperty("remoteCallerID", oldData); } } } -void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event) { +void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; #endif @@ -2875,7 +2684,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS return; } #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "ScriptManager::callEntityScriptMethod() called on correct thread [" << thread() << "] " "entityID:" << entityID << "methodName:" << methodName << "event: pointerEvent"; #endif @@ -2888,20 +2697,22 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS QWriteLocker locker { &_entityScriptsLock }; details = _entityScripts[entityID]; } - QScriptValue entityScript = details.scriptObject; // previously loaded - if (entityScript.property(methodName).isFunction()) { - QScriptValueList args; - args << entityID.toScriptValue(this); - args << event.toScriptValue(this); - callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); + ScriptValuePointer entityScript = details.scriptObject; // previously loaded + if (entityScript->property(methodName)->isFunction()) { + auto scriptEngine = engine().data(); + + ScriptValueList args; + args << entityID.toScriptValue(scriptEngine); + args << event.toScriptValue(scriptEngine); + callWithEnvironment(entityID, details.definingSandboxURL, entityScript->property(methodName), entityScript, args); } } } -void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) { +void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; #endif @@ -2913,7 +2724,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS return; } #ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " + qCDebug(scriptengine) << "ScriptManager::callEntityScriptMethod() called on correct thread [" << thread() << "] " "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; #endif @@ -2926,17 +2737,51 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS QWriteLocker locker { &_entityScriptsLock }; details = _entityScripts[entityID]; } - QScriptValue entityScript = details.scriptObject; // previously loaded - if (entityScript.property(methodName).isFunction()) { - QScriptValueList args; - args << entityID.toScriptValue(this); - args << otherID.toScriptValue(this); - args << collisionToScriptValue(this, collision); - callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); + ScriptValuePointer entityScript = details.scriptObject; // previously loaded + if (entityScript->property(methodName)->isFunction()) { + auto scriptEngine = engine().data(); + + ScriptValueList args; + args << entityID.toScriptValue(scriptEngine); + args << otherID.toScriptValue(scriptEngine); + args << collisionToScriptValue(scriptEngine, collision); + callWithEnvironment(entityID, details.definingSandboxURL, entityScript->property(methodName), entityScript, args); } } } -QString ScriptEngine::getExternalPath(ExternalResource::Bucket bucket, const QString& path) { +QString ScriptManager::getExternalPath(ExternalResource::Bucket bucket, const QString& path) { return ExternalResource::getInstance()->getUrl(bucket, path); } + +QString ScriptManager::formatException(const ScriptValuePointer& exception, bool includeExtendedDetails) { + if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { + return QString(); + } + QString note{ "UncaughtException" }; + QString result; + + if (!exception->isObject()) { + return result; + } + const auto message = exception->toString(); + const auto fileName = exception->property("fileName")->toString(); + const auto lineNumber = exception->property("lineNumber")->toString(); + const auto stacktrace = exception->property("stack")->toString(); + + if (includeExtendedDetails) { + // Display additional exception / troubleshooting hints that can be added via the custom Error .detail property + // Example difference: + // [UncaughtExceptions] Error: Can't find variable: foobar in atp:/myentity.js\n... + // [UncaughtException (construct {1eb5d3fa-23b1-411c-af83-163af7220e3f})] Error: Can't find variable: foobar in atp:/myentity.js\n... + if (exception->property("detail")->isValid()) { + note += " " + exception->property("detail")->toString(); + } + } + + result = QString(SCRIPT_EXCEPTION_FORMAT).arg(note, message, fileName, lineNumber); + if (!stacktrace.isEmpty()) { + result += QString("\n[Backtrace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace); + } + return result; +} diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h new file mode 100644 index 00000000000..ba4e15f6338 --- /dev/null +++ b/libraries/script-engine/src/ScriptManager.h @@ -0,0 +1,961 @@ +// +// ScriptManager.h +// libraries/script-engine/src +// +// Created by Brad Hefta-Gaub on 12/14/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptManager_h +#define hifi_ScriptManager_h + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "EntityItemID.h" +#include "EntitiesScriptEngineProvider.h" +#include +#include +#include + +#include "AssetScriptingInterface.h" +#include "ConsoleScriptingInterface.h" +#include "Mat4.h" +#include "PointerEvent.h" +#include "Quat.h" +#include "ScriptUUID.h" +#include "Vec3.h" + +class QScriptEngineDebugger; + +static const QString NO_SCRIPT(""); + +static const int SCRIPT_FPS = 60; +static const int DEFAULT_MAX_ENTITY_PPS = 9000; +static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900; + +class ScriptEngine; +class ScriptEngines; +class ScriptManager; +class ScriptValue; +using ScriptEnginePointer = QSharedPointer; +using ScriptManagerPointer = QSharedPointer; +using ScriptValuePointer = QSharedPointer; +using ScriptValueList = QList; + +Q_DECLARE_METATYPE(ScriptManagerPointer) + +class CallbackData { +public: + ScriptValuePointer function; + EntityItemID definingEntityIdentifier; + QUrl definingSandboxURL; +}; + +class DeferredLoadEntity { +public: + EntityItemID entityID; + QString entityScript; + //bool forceRedownload; +}; + +struct EntityScriptContentAvailable { + EntityItemID entityID; + QString scriptOrURL; + QString contents; + bool isURL; + bool success; + QString status; +}; + +typedef std::unordered_map EntityScriptContentAvailableMap; + +typedef QList CallbackList; +typedef QHash RegisteredEventHandlers; + +class EntityScriptDetails { +public: + EntityScriptStatus status { EntityScriptStatus::PENDING }; + + // If status indicates an error, this contains a human-readable string giving more information about the error. + QString errorInfo { "" }; + + QString scriptText { "" }; + ScriptValuePointer scriptObject{ ScriptValuePointer() }; + int64_t lastModified { 0 }; + QUrl definingSandboxURL { QUrl("about:EntityScript") }; +}; + +/**jsdoc + * The Script API provides facilities for working with scripts. + * + * @namespace Script + * + * @hifi-interface + * @hifi-client-entity + * @hifi-avatar + * @hifi-server-entity + * @hifi-assignment-client + * + * @property {string} context - The context that the script is running in: + *
    + *
  • "client": An Interface or avatar script.
  • + *
  • "entity_client": A client entity script.
  • + *
  • "entity_server": A server entity script.
  • + *
  • "agent": An assignment client script.
  • + *
+ * Read-only. + * @property {string} type - The type of script that is running: + *
    + *
  • "client": An Interface script.
  • + *
  • "entity_client": A client entity script.
  • + *
  • "avatar": An avatar script.
  • + *
  • "entity_server": A server entity script.
  • + *
  • "agent": An assignment client script.
  • + *
+ * Read-only. + * @property {string} filename - The filename of the script file. + * Read-only. + * @property {Script.ResourceBuckets} ExternalPaths - External resource buckets. + */ +class ScriptManager : public QObject, public EntitiesScriptEngineProvider, public QEnableSharedFromThis { + Q_OBJECT + Q_PROPERTY(QString context READ getContext) + Q_PROPERTY(QString type READ getTypeAsString) + Q_PROPERTY(QString fileName MEMBER _fileNameString CONSTANT) +public: + static const QString SCRIPT_EXCEPTION_FORMAT; + static const QString SCRIPT_BACKTRACE_SEP; + + enum Context { + CLIENT_SCRIPT, + ENTITY_CLIENT_SCRIPT, + ENTITY_SERVER_SCRIPT, + AGENT_SCRIPT + }; + + enum Type { + CLIENT, + ENTITY_CLIENT, + ENTITY_SERVER, + AGENT, + AVATAR + }; + Q_ENUM(Type) + + static int processLevelMaxRetries; + ScriptManager(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine")); + ~ScriptManager(); + + /// run the script in a dedicated thread. This will have the side effect of evalulating + /// the current script contents and calling run(). Callers will likely want to register the script with external + /// services before calling this. + void runInThread(); + + void runDebuggable(); + + /// run the script in the callers thread, exit when stop() is called. + void run(); + + QString getFilename() const; + + ScriptEnginePointer engine(); + + QList getListOfEntityScriptIDs(); + + /**jsdoc + * Stops and unloads the current script. + *

Warning: If an assignment client script, the script gets restarted after stopping.

+ * @function Script.stop + * @param {boolean} [marshal=false] - Marshal. + *

Deprecated: This parameter is deprecated and will be removed.

+ * @example Stop a script after 5s. + * Script.setInterval(function () { + * print("Hello"); + * }, 1000); + * + * Script.setTimeout(function () { + * Script.stop(true); + * }, 5000); + */ + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // NOTE - this is intended to be a public interface for Agent scripts, and local scripts, but not for EntityScripts + Q_INVOKABLE void stop(bool marshal = false); + + // Stop any evaluating scripts and wait for the scripting thread to finish. + void waitTillDoneRunning(bool shutdown = false); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can + // properly ensure they are only called on the correct thread + + /// if the script engine is not already running, this will download the URL and start the process of seting it up + /// to run... NOTE - this is used by Application currently to load the url. We don't really want it to be exposed + /// to scripts. we may not need this to be invokable + void loadURL(const QUrl& scriptURL, bool reload); + bool hasValidScriptSuffix(const QString& scriptFileName); + + /**jsdoc + * Gets the context that the script is running in: Interface/avatar, client entity, server entity, or assignment client. + * @function Script.getContext + * @returns {string} The context that the script is running in: + *
    + *
  • "client": An Interface or avatar script.
  • + *
  • "entity_client": A client entity script.
  • + *
  • "entity_server": A server entity script.
  • + *
  • "agent": An assignment client script.
  • + *
+ */ + Q_INVOKABLE QString getContext() const; + + /**jsdoc + * Checks whether the script is running as an Interface or avatar script. + * @function Script.isClientScript + * @returns {boolean} true if the script is running as an Interface or avatar script, false if it + * isn't. + */ + Q_INVOKABLE bool isClientScript() const { return _context == CLIENT_SCRIPT; } + + /**jsdoc + * Checks whether the application was compiled as a debug build. + * @function Script.isDebugMode + * @returns {boolean} true if the application was compiled as a debug build, false if it was + * compiled as a release build. + */ + Q_INVOKABLE bool isDebugMode() const; + + /**jsdoc + * Checks whether the script is running as a client entity script. + * @function Script.isEntityClientScript + * @returns {boolean} true if the script is running as a client entity script, false if it isn't. + */ + Q_INVOKABLE bool isEntityClientScript() const { return _context == ENTITY_CLIENT_SCRIPT; } + + /**jsdoc + * Checks whether the script is running as a server entity script. + * @function Script.isEntityServerScript + * @returns {boolean} true if the script is running as a server entity script, false if it isn't. + */ + Q_INVOKABLE bool isEntityServerScript() const { return _context == ENTITY_SERVER_SCRIPT; } + + /**jsdoc + * Checks whether the script is running as an assignment client script. + * @function Script.isAgentScript + * @returns {boolean} true if the script is running as an assignment client script, false if it + * isn't. + */ + Q_INVOKABLE bool isAgentScript() const { return _context == AGENT_SCRIPT; } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // NOTE - these are intended to be public interfaces available to scripts + + /**jsdoc + * @function Script.formatExecption + * @param {object} exception - Exception. + * @param {boolean} inludeExtendeDetails - Include extended details. + * @returns {string} String. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE QString formatException(const ScriptValuePointer& exception, bool includeExtendedDetails); + + /**jsdoc + * Adds a function to the list of functions called when a particular event occurs on a particular entity. + *

See also, the {@link Entities} API.

+ * @function Script.addEventHandler + * @param {Uuid} entityID - The ID of the entity. + * @param {Script.EntityEvent} eventName - The name of the event. + * @param {Script~entityEventCallback|Script~pointerEventCallback|Script~collisionEventCallback} handler - The function to + * call when the event occurs on the entity. It can be either the name of a function or an in-line definition. + * @example Report when a mouse press occurs on a particular entity. + * var entityID = Entities.addEntity({ + * type: "Box", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.5, y: 0.5, z: 0.5 }, + * lifetime: 300 // Delete after 5 minutes. + * }); + * + * function reportMousePress(entityID, event) { + * print("Mouse pressed on entity: " + JSON.stringify(event)); + * } + * + * Script.addEventHandler(entityID, "mousePressOnEntity", reportMousePress); + */ + Q_INVOKABLE void addEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler); + + /**jsdoc + * Removes a function from the list of functions called when an entity event occurs on a particular entity. + *

See also, the {@link Entities} API.

+ * @function Script.removeEventHandler + * @param {Uuid} entityID - The ID of the entity. + * @param {Script.EntityEvent} eventName - The name of the entity event. + * @param {function} handler - The name of the function to no longer call when the entity event occurs on the entity. + */ + Q_INVOKABLE void removeEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler); + + /**jsdoc + * Starts running another script in Interface, if it isn't already running. The script is not automatically loaded next + * time Interface starts. + *

Supported Script Types: Interface Scripts • Avatar Scripts

+ *

See also, {@link ScriptDiscoveryService.loadScript}.

+ * @function Script.load + * @param {string} filename - The URL of the script to load. This can be relative to the current script's URL. + * @example Load a script from another script. + * // First file: scriptA.js + * print("This is script A"); + * + * // Second file: scriptB.js + * print("This is script B"); + * Script.load("scriptA.js"); + * + * // If you run scriptB.js you should see both scripts in the Running Scripts dialog. + * // And you should see the following output: + * // This is script B + * // This is script A + */ + Q_INVOKABLE void load(const QString& loadfile); + + /**jsdoc + * Includes JavaScript from other files in the current script. If a callback is specified, the files are loaded and + * included asynchronously, otherwise they are included synchronously (i.e., script execution blocks while the files are + * included). + * @function Script.include + * @variation 0 + * @param {string[]} filenames - The URLs of the scripts to include. Each can be relative to the current script. + * @param {function} [callback=null] - The function to call back when the scripts have been included. It can be either the + * name of a function or an in-line definition. + */ + Q_INVOKABLE void include(const QStringList& includeFiles, ScriptValuePointer callback = ScriptValuePointer()); + + /**jsdoc + * Includes JavaScript from another file in the current script. If a callback is specified, the file is loaded and included + * asynchronously, otherwise it is included synchronously (i.e., script execution blocks while the file is included). + * @function Script.include + * @param {string} filename - The URL of the script to include. It can be relative to the current script. + * @param {function} [callback=null] - The function to call back when the script has been included. It can be either the + * name of a function or an in-line definition. + * @example Include a script file asynchronously. + * // First file: scriptA.js + * print("This is script A"); + * + * // Second file: scriptB.js + * print("This is script B"); + * Script.include("scriptA.js", function () { + * print("Script A has been included"); + * }); + * + * // If you run scriptB.js you should see only scriptB.js in the running scripts list. + * // And you should see the following output: + * // This is script B + * // This is script A + * // Script A has been included + */ + Q_INVOKABLE void include(const QString& includeFile, ScriptValuePointer callback = ScriptValuePointer()); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MODULE related methods + + /**jsdoc + * Provides access to methods or objects provided in an external JavaScript or JSON file. + * See {@link https://docs.vircadia.dev/script/js-tips.html} for further details. + * @function Script.require + * @param {string} module - The module to use. May be a JavaScript file, a JSON file, or the name of a system module such + * as "appUi" (i.e., the "appUi.js" system module JavaScript file). + * @returns {object|array} The value assigned to module.exports in the JavaScript file, or the value defined + * in the JSON file. + */ + Q_INVOKABLE ScriptValuePointer require(const QString& moduleId); + + /**jsdoc + * @function Script.resetModuleCache + * @param {boolean} [deleteScriptCache=false] - Delete script cache. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void resetModuleCache(bool deleteScriptCache = false); + + ScriptValuePointer currentModule(); + bool registerModuleWithParent(const ScriptValuePointer& module, const ScriptValuePointer& parent); + ScriptValuePointer newModule(const QString& modulePath, const ScriptValuePointer& parent = ScriptValuePointer()); + QVariantMap fetchModuleSource(const QString& modulePath, const bool forceDownload = false); + ScriptValuePointer instantiateModule(const ScriptValuePointer& module, const QString& sourceCode); + + Q_INVOKABLE ScriptValuePointer evaluate(const QString& program, const QString& fileName = QString()); + + /**jsdoc + * Calls a function repeatedly, at a set interval. + * @function Script.setInterval + * @param {function} function - The function to call. This can be either the name of a function or an in-line definition. + * @param {number} interval - The interval at which to call the function, in ms. + * @returns {object} A handle to the interval timer. This can be used in {@link Script.clearInterval}. + * @example Print a message every second. + * Script.setInterval(function () { + * print("Interval timer fired"); + * }, 1000); + */ + Q_INVOKABLE QObject* setInterval(const ScriptValuePointer& function, int intervalMS); + + /**jsdoc + * Calls a function once, after a delay. + * @function Script.setTimeout + * @param {function} function - The function to call. This can be either the name of a function or an in-line definition. + * @param {number} timeout - The delay after which to call the function, in ms. + * @returns {object} A handle to the timeout timer. This can be used in {@link Script.clearTimeout}. + * @example Print a message once, after a second. + * Script.setTimeout(function () { + * print("Timeout timer fired"); + * }, 1000); + */ + Q_INVOKABLE QObject* setTimeout(const ScriptValuePointer& function, int timeoutMS); + + /**jsdoc + * Stops an interval timer set by {@link Script.setInterval|setInterval}. + * @function Script.clearInterval + * @param {object} timer - The interval timer to stop. + * @example Stop an interval timer. + * // Print a message every second. + * var timer = Script.setInterval(function () { + * print("Interval timer fired"); + * }, 1000); + * + * // Stop the timer after 10 seconds. + * Script.setTimeout(function () { + * print("Stop interval timer"); + * Script.clearInterval(timer); + * }, 10000); + */ + Q_INVOKABLE void clearInterval(QObject* timer) { stopTimer(reinterpret_cast(timer)); } + + /**jsdoc + * Stops a timeout timer set by {@link Script.setTimeout|setTimeout}. + * @function Script.clearTimeout + * @param {object} timer - The timeout timer to stop. + * @example Stop a timeout timer. + * // Print a message after two seconds. + * var timer = Script.setTimeout(function () { + * print("Timer fired"); + * }, 2000); + * + * // Uncomment the following line to stop the timer from firing. + * //Script.clearTimeout(timer); + */ + Q_INVOKABLE void clearTimeout(QObject* timer) { stopTimer(reinterpret_cast(timer)); } + + /**jsdoc + * Prints a message to the program log and emits {@link Script.printedMessage}. + *

Alternatively, you can use {@link print} or one of the {@link console} API methods.

+ * @function Script.print + * @param {string} message - The message to print. + */ + Q_INVOKABLE void print(const QString& message); + + /**jsdoc + * Resolves a relative path to an absolute path. The relative path is relative to the script's location. + * @function Script.resolvePath + * @param {string} path - The relative path to resolve. + * @returns {string} The absolute path. + * @example Report the directory and filename of the running script. + * print(Script.resolvePath("")); + * @example Report the directory of the running script. + * print(Script.resolvePath(".")); + * @example Report the path to a file located relative to the running script. + * print(Script.resolvePath("../assets/sounds/hello.wav")); + */ + Q_INVOKABLE QUrl resolvePath(const QString& path) const; + + /**jsdoc + * Gets the path to the resources directory for QML files. + * @function Script.resourcesPath + * @returns {string} The path to the resources directory for QML files. + */ + Q_INVOKABLE QUrl resourcesPath() const; + + /**jsdoc + * Starts timing a section of code in order to send usage data about it to Vircadia. Shouldn't be used outside of the + * standard scripts. + * @function Script.beginProfileRange + * @param {string} label - A name that identifies the section of code. + */ + Q_INVOKABLE void beginProfileRange(const QString& label) const; + + /**jsdoc + * Finishes timing a section of code in order to send usage data about it to Vircadia. Shouldn't be used outside of + * the standard scripts. + * @function Script.endProfileRange + * @param {string} label - A name that identifies the section of code. + */ + Q_INVOKABLE void endProfileRange(const QString& label) const; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Entity Script Related methods + + /**jsdoc + * Checks whether an entity has an entity script running. + * @function Script.isEntityScriptRunning + * @param {Uuid} entityID - The ID of the entity. + * @returns {boolean} true if the entity has an entity script running, false if it doesn't. + */ + Q_INVOKABLE bool isEntityScriptRunning(const EntityItemID& entityID) { + QReadLocker locker { &_entityScriptsLock }; + auto it = _entityScripts.constFind(entityID); + return it != _entityScripts.constEnd() && it->status == EntityScriptStatus::RUNNING; + } + QVariant cloneEntityScriptDetails(const EntityItemID& entityID); + QFuture getLocalEntityScriptDetails(const EntityItemID& entityID) override; + + /**jsdoc + * @function Script.loadEntityScript + * @param {Uuid} entityID - Entity ID. + * @param {string} script - Script. + * @param {boolean} forceRedownload - Force re-download. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload); + + /**jsdoc + * @function Script.unloadEntityScript + * @param {Uuid} entityID - Entity ID. + * @param {boolean} [shouldRemoveFromMap=false] - Should remove from map. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap = false); // will call unload method + + /**jsdoc + * @function Script.unloadAllEntityScripts + * @param {boolean} [blockingCall=false] - Wait for completion if call moved to another thread. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void unloadAllEntityScripts(bool blockingCall = false); + + /**jsdoc + * Calls a method in an entity script. + * @function Script.callEntityScriptMethod + * @param {Uuid} entityID - The ID of the entity running the entity script. + * @param {string} methodName - The name of the method to call. + * @param {string[]} [parameters=[]] - The parameters to call the specified method with. + * @param {Uuid} [remoteCallerID=Uuid.NULL] - An ID that identifies the caller. + */ + Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, + const QStringList& params = QStringList(), + const QUuid& remoteCallerID = QUuid()) override; + + /**jsdoc + * Calls a method in an entity script. + * @function Script.callEntityScriptMethod + * @param {Uuid} entityID - Entity ID. + * @param {string} methodName - Method name. + * @param {PointerEvent} event - Pointer event. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const PointerEvent& event); + + /**jsdoc + * Calls a method in an entity script. + * @function Script.callEntityScriptMethod + * @param {Uuid} entityID - Entity ID. + * @param {string} methodName - Method name. + * @param {Uuid} otherID - Other entity ID. + * @param {Collision} collision - Collision. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const EntityItemID& otherID, const Collision& collision); + + /**jsdoc + * @function Script.generateUUID + * @returns {Uuid} A new UUID. + * @deprecated This function is deprecated and will be removed. Use {@link Uuid(0).generate|Uuid.generate} instead. + */ + Q_INVOKABLE QUuid generateUUID() { return QUuid::createUuid(); } + + void setType(Type type) { _type = type; }; + Type getType() { return _type; }; + QString getTypeAsString() const; + + bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget + bool isRunning() const { return _isRunning; } // used by ScriptWidget + + // this is used by code in ScriptEngines.cpp during the "reload all" operation + bool isStopping() const { return _isStopping; } + + bool isDebuggable() const { return _debuggable; } + + void disconnectNonEssentialSignals(); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // These are currently used by Application to track if a script is user loaded or not. Consider finding a solution + // inside of Application so that the ScriptManager class is not polluted by this notion + void setUserLoaded(bool isUserLoaded) { _isUserLoaded = isUserLoaded; } + bool isUserLoaded() const { return _isUserLoaded; } + + void setQuitWhenFinished(const bool quitWhenFinished) { _quitWhenFinished = quitWhenFinished; } + bool isQuitWhenFinished() const { return _quitWhenFinished; } + + void setEmitScriptUpdatesFunction(std::function func) { _emitScriptUpdates = func; } + + void scriptErrorMessage(const QString& message); + void scriptWarningMessage(const QString& message); + void scriptInfoMessage(const QString& message); + void scriptPrintedMessage(const QString& message); + void clearDebugLogWindow(); + int getNumRunningEntityScripts() const; + bool getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const; + bool hasEntityScriptDetails(const EntityItemID& entityID) const; + + void setScriptEngines(QSharedPointer& scriptEngines) { _scriptEngines = scriptEngines; } + + /**jsdoc + * Gets the URL for an asset in an external resource bucket. (The location where the bucket is hosted may change over time + * but this method will return the asset's current URL.) + * @function Script.getExternalPath + * @param {Script.ResourceBucket} bucket - The external resource bucket that the asset is in. + * @param {string} path - The path within the external resource bucket where the asset is located. + *

Normally, this should start with a path or filename to be appended to the bucket URL. + * Alternatively, it can be a relative path starting with ./ or ../, to navigate within the + * resource bucket's URL.

+ * @Returns {string} The URL of an external asset. + * @example Report the URL of a default particle. + * print(Script.getExternalPath(Script.ExternalPaths.Assets, "Bazaar/Assets/Textures/Defaults/Interface/default_particle.png")); + * @example Report the root directory where the Vircadia assets are located. + * print(Script.getExternalPath(Script.ExternalPaths.Assets, ".")); + */ + Q_INVOKABLE QString getExternalPath(ExternalResource::Bucket bucket, const QString& path); + +public slots: + + /**jsdoc + * @function Script.callAnimationStateHandler + * @param {function} callback - Callback function. + * @param {object} parameters - Parameters. + * @param {string[]} names - Names. + * @param {boolean} useNames - Use names. + * @param {function} resultHandler - Result handler. + * @deprecated This function is deprecated and will be removed. + */ + void callAnimationStateHandler(ScriptValuePointer callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); + + /**jsdoc + * @function Script.updateMemoryCost + * @param {number} deltaSize - Delta size. + * @deprecated This function is deprecated and will be removed. + */ + void updateMemoryCost(const qint64&); + +signals: + + /**jsdoc + * @function Script.scriptLoaded + * @param {string} filename - File name. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void scriptLoaded(const QString& scriptFilename); + + /**jsdoc + * @function Script.errorLoadingScript + * @param {string} filename - File name. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void errorLoadingScript(const QString& scriptFilename); + + /**jsdoc + * Triggered frequently at a system-determined interval. + * @function Script.update + * @param {number} deltaTime - The time since the last update, in s. + * @returns {Signal} + * @example Report script update intervals. + * Script.update.connect(function (deltaTime) { + * print("Update: " + deltaTime); + * }); + */ + void update(float deltaTime); + + /**jsdoc + * Triggered when the script is stopping. + * @function Script.scriptEnding + * @returns {Signal} + * @example Report when a script is stopping. + * print("Script started"); + * + * Script.scriptEnding.connect(function () { + * print("Script ending"); + * }); + * + * Script.setTimeout(function () { + * print("Stopping script"); + * Script.stop(); + * }, 1000); + */ + void scriptEnding(); + + /**jsdoc + * @function Script.finished + * @param {string} filename - File name. + * @param {object} engine - Engine. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void finished(const QString& fileNameString, ScriptManagerPointer); + + /**jsdoc + * @function Script.cleanupMenuItem + * @param {string} menuItem - Menu item. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void cleanupMenuItem(const QString& menuItemString); + + /**jsdoc + * Triggered when the script prints a message to the program log via {@link print}, {@link Script.print}, + * {@link console.log}, {@link console.debug}, {@link console.group}, {@link console.groupEnd}, {@link console.time}, or + * {@link console.timeEnd}. + * @function Script.printedMessage + * @param {string} message - The message. + * @param {string} scriptName - The name of the script that generated the message. + * @returns {Signal} + */ + void printedMessage(const QString& message, const QString& scriptName); + + /**jsdoc + * Triggered when the script generates an error, {@link console.error} or {@link console.exception} is called, or + * {@link console.assert} is called and fails. + * @function Script.errorMessage + * @param {string} message - The error message. + * @param {string} scriptName - The name of the script that generated the error message. + * @returns {Signal} + */ + void errorMessage(const QString& message, const QString& scriptName); + + /**jsdoc + * Triggered when the script generates a warning or {@link console.warn} is called. + * @function Script.warningMessage + * @param {string} message - The warning message. + * @param {string} scriptName - The name of the script that generated the warning message. + * @returns {Signal} + */ + void warningMessage(const QString& message, const QString& scriptName); + + /**jsdoc + * Triggered when the script generates an information message or {@link console.info} is called. + * @function Script.infoMessage + * @param {string} message - The information message. + * @param {string} scriptName - The name of the script that generated the information message. + * @returns {Signal} + */ + void infoMessage(const QString& message, const QString& scriptName); + + /**jsdoc + * Triggered when the running state of the script changes, e.g., from running to stopping. + * @function Script.runningStateChanged + * @returns {Signal} + */ + void runningStateChanged(); + + /**jsdoc + * @function Script.clearDebugWindow + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void clearDebugWindow(); + + /**jsdoc + * @function Script.loadScript + * @param {string} scriptName - Script name. + * @param {boolean} isUserLoaded - Is user loaded. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void loadScript(const QString& scriptName, bool isUserLoaded); + + /**jsdoc + * @function Script.reloadScript + * @param {string} scriptName - Script name. + * @param {boolean} isUserLoaded - Is user loaded. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + void reloadScript(const QString& scriptName, bool isUserLoaded); + + /**jsdoc + * Triggered when the script has stopped. + * @function Script.doneRunning + * @returns {Signal} + */ + void doneRunning(); + + /**jsdoc + * @function Script.entityScriptDetailsUpdated + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + // Emitted when an entity script is added or removed, or when the status of an entity + // script is updated (goes from RUNNING to ERROR_RUNNING_SCRIPT, for example) + void entityScriptDetailsUpdated(); + + /**jsdoc + * Triggered when the script starts for the user. See also, {@link Entities.preload}. + *

Supported Script Types: Client Entity Scripts • Server Entity Scripts

+ * @function Script.entityScriptPreloadFinished + * @param {Uuid} entityID - The ID of the entity that the script is running in. + * @returns {Signal} + * @example Get the ID of the entity that a client entity script is running in. + * var entityScript = function () { + * this.entityID = Uuid.NULL; + * }; + * + * Script.entityScriptPreloadFinished.connect(function (entityID) { + * this.entityID = entityID; + * print("Entity ID: " + this.entityID); + * }); + * + * var entityID = Entities.addEntity({ + * type: "Box", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.5, y: 0.5, z: 0.5 }, + * color: { red: 255, green: 0, blue: 0 }, + * script: "(" + entityScript + ")", // Could host the script on a Web server instead. + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + // Emitted when an entity script has finished running preload + void entityScriptPreloadFinished(const EntityItemID& entityID); + + /**jsdoc + * Triggered when a script generates an unhandled exception. + * @function Script.unhandledException + * @param {object} exception - The details of the exception. + * @returns {Signal} + * @example Report the details of an unhandled exception. + * Script.unhandledException.connect(function (exception) { + * print("Unhandled exception: " + JSON.stringify(exception)); + * }); + * var properties = JSON.parse("{ x: 1"); // Invalid JSON string. + */ + void unhandledException(const ScriptValuePointer& exception); + +protected: + void init(); + + /**jsdoc + * @function Script.executeOnScriptThread + * @param {function} function - Function. + * @param {ConnectionType} [type=2] - Connection type. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void executeOnScriptThread(std::function function, const Qt::ConnectionType& type = Qt::QueuedConnection ); + + /**jsdoc + * @function Script._requireResolve + * @param {string} module - Module. + * @param {string} [relativeTo=""] - Relative to. + * @returns {string} Result. + * @deprecated This function is deprecated and will be removed. + */ + // note: this is not meant to be called directly, but just to have QMetaObject take care of wiring it up in general; + // then inside of init() we just have to do "Script.require.resolve = Script._requireResolve;" + Q_INVOKABLE QString _requireResolve(const QString& moduleId, const QString& relativeTo = QString()); + + QString logException(const ScriptValuePointer& exception); + void timerFired(); + void stopAllTimers(); + void stopAllTimersForEntityScript(const EntityItemID& entityID); + void refreshFileScript(const EntityItemID& entityID); + void updateEntityScriptStatus(const EntityItemID& entityID, const EntityScriptStatus& status, const QString& errorInfo = QString()); + void setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details); + void setParentURL(const QString& parentURL) { _parentURL = parentURL; } + + QObject* setupTimerWithInterval(const ScriptValuePointer& function, int intervalMS, bool isSingleShot); + void stopTimer(QTimer* timer); + + QHash _registeredHandlers; + void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, ScriptValueList eventHanderArgs); + + /**jsdoc + * @function Script.entityScriptContentAvailable + * @param {Uuid} entityID - Entity ID. + * @param {string} scriptOrURL - Path. + * @param {string} contents - Contents. + * @param {boolean} isURL - Is a URL. + * @param {boolean} success - Success. + * @param {string} status - Status. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success, const QString& status); + + EntityItemID currentEntityIdentifier; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution. + QUrl currentSandboxURL; // The toplevel url string for the entity script that loaded the code being executed, else empty. + void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation); + void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, ScriptValuePointer function, ScriptValuePointer thisObject, ScriptValueList args); + + Context _context; + Type _type; + ScriptEnginePointer _engine; + QString _scriptContents; + QString _parentURL; + std::atomic _isFinished { false }; + std::atomic _isRunning { false }; + std::atomic _isStopping { false }; + bool _isInitialized { false }; + QHash _timerFunctionMap; + QSet _includedURLs; + mutable QReadWriteLock _entityScriptsLock { QReadWriteLock::Recursive }; + QHash _entityScripts; + EntityScriptContentAvailableMap _contentAvailableQueue; + + bool _isThreaded { false }; + QScriptEngineDebugger* _debugger { nullptr }; + bool _debuggable { false }; + qint64 _lastUpdate; + + QString _fileNameString; + Quat _quatLibrary; + Vec3 _vec3Library; + Mat4 _mat4Library; + ScriptUUID _uuidLibrary; + ConsoleScriptingInterface _consoleScriptingInterface; + std::atomic _isUserLoaded { false }; + bool _isReloading { false }; + + std::atomic _quitWhenFinished; + + AssetScriptingInterface* _assetScriptingInterface; + + std::function _emitScriptUpdates{ []() { return true; } }; + + std::recursive_mutex _lock; + + std::chrono::microseconds _totalTimerExecution { 0 }; + + static const QString _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS; + + Setting::Handle _enableExtendedJSExceptions { _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS, true }; + + QWeakPointer _scriptEngines; + + friend ScriptManagerPointer newScriptManager(Context context, const QString& scriptContents, const QString& fileNameString); +}; + +ScriptManagerPointer newScriptManager(ScriptManager::Context context, + const QString& scriptContents, + const QString& fileNameString); +ScriptManagerPointer scriptManagerFactory(ScriptManager::Context context, + const QString& scriptContents, + const QString& fileNameString); + +#endif // hifi_ScriptManager_h diff --git a/libraries/script-engine/src/ScriptProgram.h b/libraries/script-engine/src/ScriptProgram.h new file mode 100644 index 00000000000..1c49f042d69 --- /dev/null +++ b/libraries/script-engine/src/ScriptProgram.h @@ -0,0 +1,45 @@ +// +// ScriptProgram.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/2/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptProgram_h +#define hifi_ScriptProgram_h + +#include + +class ScriptProgram; +class ScriptSyntaxCheckResult; +using ScriptProgramPointer = QSharedPointer; +using ScriptSyntaxCheckResultPointer = QSharedPointer; + +class ScriptProgram { +public: + virtual ScriptSyntaxCheckResultPointer checkSyntax() const = 0; + virtual QString fileName() const = 0; + virtual QString sourceCode() const = 0; +}; + +class ScriptSyntaxCheckResult { +public: + enum State + { + Error = 0, + Intermediate = 1, + Valid = 2 + }; + +public: + virtual int errorColumnNumber() const = 0; + virtual int errorLineNumber() const = 0; + virtual QString errorMessage() const = 0; + virtual State state() const = 0; +}; + +#endif // hifi_ScriptProgram_h \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptUUID.cpp b/libraries/script-engine/src/ScriptUUID.cpp index f88803c87c3..b9661e31eda 100644 --- a/libraries/script-engine/src/ScriptUUID.cpp +++ b/libraries/script-engine/src/ScriptUUID.cpp @@ -17,6 +17,7 @@ #include "ScriptEngineLogging.h" #include "ScriptEngine.h" +#include "ScriptManager.h" QUuid ScriptUUID::fromString(const QString& s) { return QUuid(s); @@ -42,7 +43,7 @@ void ScriptUUID::print(const QString& label, const QUuid& id) { QString message = QString("%1 %2").arg(qPrintable(label)); message = message.arg(id.toString()); qCDebug(scriptengine) << message; - if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->print(message); + if (ScriptManager* scriptManager = engine()->manager()) { + scriptManager->print(message); } } diff --git a/libraries/script-engine/src/ScriptUUID.h b/libraries/script-engine/src/ScriptUUID.h index b667447aaa1..5bfde9131d3 100644 --- a/libraries/script-engine/src/ScriptUUID.h +++ b/libraries/script-engine/src/ScriptUUID.h @@ -16,7 +16,8 @@ #include #include -#include + +#include "Scriptable.h" /**jsdoc * The Uuid API provides facilities for working with UUIDs. @@ -34,7 +35,7 @@ */ /// Scriptable interface for a UUID helper class object. Used exclusively in the JavaScript API -class ScriptUUID : public QObject, protected QScriptable { +class ScriptUUID : public QObject, protected Scriptable { Q_OBJECT Q_PROPERTY(QString NULL READ NULL_UUID CONSTANT) // String for use in scripts. diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h new file mode 100644 index 00000000000..b3c90e8e444 --- /dev/null +++ b/libraries/script-engine/src/ScriptValue.h @@ -0,0 +1,206 @@ +// +// ScriptValue.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 4/25/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptValue_h +#define hifi_ScriptValue_h + +#include +#include +#include +#include + +class QObject; +class ScriptEngine; +class ScriptValue; +class ScriptValueIterator; +using ScriptEnginePointer = QSharedPointer; +using ScriptValuePointer = QSharedPointer; +using ScriptValueList = QList; +using ScriptValueIteratorPointer = QSharedPointer; + +class ScriptValue { +public: + enum ResolveFlag + { + ResolveLocal = 0, + ResolvePrototype = 1, + }; + using ResolveFlags = QFlags; + + enum PropertyFlag + { + ReadOnly = 0x00000001, + Undeletable = 0x00000002, + SkipInEnumeration = 0x00000004, + PropertyGetter = 0x00000008, + PropertySetter = 0x00000010, + KeepExistingFlags = 0x00000800, + }; + Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag); + +public: + virtual ScriptValuePointer call(const ScriptValuePointer& thisObject = ScriptValuePointer(), + const ScriptValueList& args = ScriptValueList()) = 0; + virtual ScriptValuePointer call(const ScriptValuePointer& thisObject, const ScriptValuePointer& arguments) = 0; + virtual ScriptValuePointer construct(const ScriptValueList& args = ScriptValueList()) = 0; + virtual ScriptValuePointer construct(const ScriptValuePointer& arguments) = 0; + virtual ScriptEnginePointer engine() const = 0; + inline bool equals(const ScriptValuePointer& other) const; + inline bool isArray() const; + inline bool isBool() const; + inline bool isError() const; + inline bool isFunction() const; + inline bool isNumber() const; + inline bool isNull() const; + inline bool isObject() const; + inline bool isString() const; + inline bool isUndefined() const; + inline bool isValid() const; + inline bool isVariant() const; + virtual ScriptValueIteratorPointer newIterator() = 0; + virtual ScriptValuePointer property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const = 0; + virtual ScriptValuePointer property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const = 0; + virtual void setProperty(const QString& name, + const ScriptValuePointer& value, + const PropertyFlags& flags = KeepExistingFlags) = 0; + virtual void setProperty(quint32 arrayIndex, + const ScriptValuePointer& value, + const PropertyFlags& flags = KeepExistingFlags) = 0; + template void setProperty(const QString& name, const TYP& value, + const PropertyFlags& flags = KeepExistingFlags); + template void setProperty(quint32 arrayIndex, const TYP& value, + const PropertyFlags& flags = KeepExistingFlags); + virtual void setPrototype(const ScriptValuePointer& prototype) = 0; + virtual bool strictlyEquals(const ScriptValuePointer& other) const = 0; + + virtual bool toBool() const = 0; + virtual qint32 toInt32() const = 0; + virtual double toInteger() const = 0; + virtual double toNumber() const = 0; + virtual QString toString() const = 0; + virtual quint16 toUInt16() const = 0; + virtual quint32 toUInt32() const = 0; + virtual QVariant toVariant() const = 0; + virtual QObject* toQObject() const = 0; + +protected: + virtual bool equalsInternal(const ScriptValuePointer& other) const = 0; + virtual bool isArrayInternal() const = 0; + virtual bool isBoolInternal() const = 0; + virtual bool isErrorInternal() const = 0; + virtual bool isFunctionInternal() const = 0; + virtual bool isNumberInternal() const = 0; + virtual bool isNullInternal() const = 0; + virtual bool isObjectInternal() const = 0; + virtual bool isStringInternal() const = 0; + virtual bool isUndefinedInternal() const = 0; + virtual bool isValidInternal() const = 0; + virtual bool isVariantInternal() const = 0; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptValue::PropertyFlags) + +bool ScriptValue::equals(const ScriptValuePointer& other) const { + if (this == NULL || !other) { + return (this == NULL) == !other; + } + return equalsInternal(other); +} + +bool ScriptValue::isArray() const { + assert(this != NULL); + if (this == NULL) return false; + return isArrayInternal(); +} + +bool ScriptValue::isBool() const { + assert(this != NULL); + if (this == NULL) + return false; + return isBoolInternal(); +} + +bool ScriptValue::isError() const { + assert(this != NULL); + if (this == NULL) + return false; + return isErrorInternal(); +} + +bool ScriptValue::isFunction() const { + assert(this != NULL); + if (this == NULL) + return false; + return isFunctionInternal(); +} + +bool ScriptValue::isNumber() const { + assert(this != NULL); + if (this == NULL) + return false; + return isNumberInternal(); +} + +bool ScriptValue::isNull() const { + assert(this != NULL); + if (this == NULL) + return false; + return isNullInternal(); +} + +bool ScriptValue::isObject() const { + assert(this != NULL); + if (this == NULL) + return false; + return isObjectInternal(); +} + +bool ScriptValue::isString() const { + assert(this != NULL); + if (this == NULL) + return false; + return isStringInternal(); +} + +bool ScriptValue::isUndefined() const { + assert(this != NULL); + if (this == NULL) + return true; + return isUndefinedInternal(); +} + +bool ScriptValue::isValid() const { + assert(this != NULL); + if (this == NULL) + return false; + return isValidInternal(); +} + +bool ScriptValue::isVariant() const { + assert(this != NULL); + if (this == NULL) + return false; + return isVariantInternal(); +} + +template +void ScriptValue::setProperty(const QString& name, const TYP& value, const PropertyFlags& flags) { + setProperty(name, engine()->newValue(value), flags); +} + +template +void ScriptValue::setProperty(quint32 arrayIndex, const TYP& value, const PropertyFlags& flags) { + setProperty(arrayIndex, engine()->newValue(value), flags); +} + +template +T scriptvalue_cast(const ScriptValuePointer& value); + +#endif // hifi_ScriptValue_h \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptValueIterator.h b/libraries/script-engine/src/ScriptValueIterator.h new file mode 100644 index 00000000000..cea07de415a --- /dev/null +++ b/libraries/script-engine/src/ScriptValueIterator.h @@ -0,0 +1,32 @@ +// +// ScriptValueIterator.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/2/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptValueIterator_h +#define hifi_ScriptValueIterator_h + +#include +#include + +#include "ScriptValue.h" + +class ScriptValueIterator; +using ScriptValueIteratorPointer = QSharedPointer; + +class ScriptValueIterator { +public: + virtual ScriptValue::PropertyFlags flags() const = 0; + virtual bool hasNext() const = 0; + virtual QString name() const = 0; + virtual void next() = 0; + virtual ScriptValuePointer value() const = 0; +}; + +#endif // hifi_ScriptValueIterator_h \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp new file mode 100644 index 00000000000..777e3296f7c --- /dev/null +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -0,0 +1,888 @@ +// +// ScriptValueUtils.cpp +// libraries/shared/src +// +// Created by Anthony Thibault on 4/15/16. +// Copyright 2016 High Fidelity, Inc. +// +// Utilities for working with QtScriptValues +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptValueUtils.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ScriptEngine.h" +#include "ScriptEngineCast.h" +#include "ScriptValueIterator.h" + +bool isListOfStrings(const ScriptValuePointer& arg) { + if (!arg->isArray()) { + return false; + } + + auto lengthProperty = arg->property("length"); + if (!lengthProperty->isNumber()) { + return false; + } + + int length = lengthProperty->toInt32(); + for (int i = 0; i < length; i++) { + if (!arg->property(i)->isString()) { + return false; + } + } + + return true; +} + +void registerMetaTypes(ScriptEngine* engine) { + scriptRegisterMetaType(engine, vec2ToScriptValue, vec2FromScriptValue); + scriptRegisterMetaType(engine, vec3ToScriptValue, vec3FromScriptValue); + scriptRegisterMetaType(engine, u8vec3ToScriptValue, u8vec3FromScriptValue); + scriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); + scriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); + scriptRegisterMetaType(engine, mat4toScriptValue, mat4FromScriptValue); + + scriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue); + scriptRegisterMetaType(engine, qVectorQuatToScriptValue, qVectorQuatFromScriptValue); + scriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue); + scriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue); + scriptRegisterMetaType(engine, qVectorIntToScriptValue, qVectorIntFromScriptValue); + scriptRegisterMetaType(engine, qVectorQUuidToScriptValue, qVectorQUuidFromScriptValue); + + scriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue); + scriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue); + scriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue); + scriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); + + scriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); + scriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); + scriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); + scriptRegisterMetaType(engine, aaCubeToScriptValue, aaCubeFromScriptValue); + + scriptRegisterMetaType(engine, stencilMaskModeToScriptValue, stencilMaskModeFromScriptValue); + + scriptRegisterMetaType(engine, promiseToScriptValue, promiseFromScriptValue); + + scriptRegisterSequenceMetaType>(engine); +} + +ScriptValuePointer vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2) { + auto prototype = engine->globalObject()->property("__hifi_vec2__"); + if (!prototype->property("defined")->toBool()) { + prototype = engine->evaluate( + "__hifi_vec2__ = Object.defineProperties({}, { " + "defined: { value: true }," + "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," + "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," + "u: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," + "v: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }" + "})"); + } + ScriptValuePointer value = engine->newObject(); + value->setProperty("x", vec2.x); + value->setProperty("y", vec2.y); + value->setPrototype(prototype); + return value; +} + +void vec2FromScriptValue(const ScriptValuePointer& object, glm::vec2& vec2) { + if (object->isNumber()) { + vec2 = glm::vec2(object->toVariant().toFloat()); + } else if (object->isArray()) { + QVariantList list = object->toVariant().toList(); + if (list.length() == 2) { + vec2.x = list[0].toFloat(); + vec2.y = list[1].toFloat(); + } + } else { + ScriptValuePointer x = object->property("x"); + if (!x->isValid()) { + x = object->property("u"); + } + + ScriptValuePointer y = object->property("y"); + if (!y->isValid()) { + y = object->property("v"); + } + + vec2.x = x->toVariant().toFloat(); + vec2.y = y->toVariant().toFloat(); + } +} + +ScriptValuePointer vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) { + auto prototype = engine->globalObject()->property("__hifi_vec3__"); + if (!prototype->property("defined")->toBool()) { + prototype = engine->evaluate( + "__hifi_vec3__ = Object.defineProperties({}, { " + "defined: { value: true }," + "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," + "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," + "2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }," + "r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," + "g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," + "b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }," + "red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," + "green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," + "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }" + "})"); + } + ScriptValuePointer value = engine->newObject(); + value->setProperty("x", vec3.x); + value->setProperty("y", vec3.y); + value->setProperty("z", vec3.z); + value->setPrototype(prototype); + return value; +} + +ScriptValuePointer vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) { + auto prototype = engine->globalObject()->property("__hifi_vec3_color__"); + if (!prototype->property("defined")->toBool()) { + prototype = engine->evaluate( + "__hifi_vec3_color__ = Object.defineProperties({}, { " + "defined: { value: true }," + "0: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," + "1: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," + "2: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }," + "r: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," + "g: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," + "b: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }," + "x: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," + "y: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," + "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }" + "})"); + } + ScriptValuePointer value = engine->newObject(); + value->setProperty("red", vec3.x); + value->setProperty("green", vec3.y); + value->setProperty("blue", vec3.z); + value->setPrototype(prototype); + return value; +} + +void vec3FromScriptValue(const ScriptValuePointer& object, glm::vec3& vec3) { + if (object->isNumber()) { + vec3 = glm::vec3(object->toVariant().toFloat()); + } else if (object->isString()) { + QColor qColor(object->toString()); + if (qColor.isValid()) { + vec3.x = qColor.red(); + vec3.y = qColor.green(); + vec3.z = qColor.blue(); + } + } else if (object->isArray()) { + QVariantList list = object->toVariant().toList(); + if (list.length() == 3) { + vec3.x = list[0].toFloat(); + vec3.y = list[1].toFloat(); + vec3.z = list[2].toFloat(); + } + } else { + ScriptValuePointer x = object->property("x"); + if (!x->isValid()) { + x = object->property("r"); + } + if (!x->isValid()) { + x = object->property("red"); + } + + ScriptValuePointer y = object->property("y"); + if (!y->isValid()) { + y = object->property("g"); + } + if (!y->isValid()) { + y = object->property("green"); + } + + ScriptValuePointer z = object->property("z"); + if (!z->isValid()) { + z = object->property("b"); + } + if (!z->isValid()) { + z = object->property("blue"); + } + + vec3.x = x->toVariant().toFloat(); + vec3.y = y->toVariant().toFloat(); + vec3.z = z->toVariant().toFloat(); + } +} + +ScriptValuePointer u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) { + auto prototype = engine->globalObject()->property("__hifi_u8vec3__"); + if (!prototype->property("defined")->toBool()) { + prototype = engine->evaluate( + "__hifi_u8vec3__ = Object.defineProperties({}, { " + "defined: { value: true }," + "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," + "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," + "2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }," + "r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," + "g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," + "b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }," + "red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," + "green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," + "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }" + "})"); + } + ScriptValuePointer value = engine->newObject(); + value->setProperty("x", vec3.x); + value->setProperty("y", vec3.y); + value->setProperty("z", vec3.z); + value->setPrototype(prototype); + return value; +} + +ScriptValuePointer u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) { + auto prototype = engine->globalObject()->property("__hifi_u8vec3_color__"); + if (!prototype->property("defined")->toBool()) { + prototype = engine->evaluate( + "__hifi_u8vec3_color__ = Object.defineProperties({}, { " + "defined: { value: true }," + "0: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," + "1: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," + "2: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }," + "r: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," + "g: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," + "b: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }," + "x: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," + "y: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," + "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }" + "})"); + } + ScriptValuePointer value = engine->newObject(); + value->setProperty("red", vec3.x); + value->setProperty("green", vec3.y); + value->setProperty("blue", vec3.z); + value->setPrototype(prototype); + return value; +} + +void u8vec3FromScriptValue(const ScriptValuePointer& object, glm::u8vec3& vec3) { + if (object->isNumber()) { + vec3 = glm::vec3(object->toVariant().toUInt()); + } else if (object->isString()) { + QColor qColor(object->toString()); + if (qColor.isValid()) { + vec3.x = (uint8_t)qColor.red(); + vec3.y = (uint8_t)qColor.green(); + vec3.z = (uint8_t)qColor.blue(); + } + } else if (object->isArray()) { + QVariantList list = object->toVariant().toList(); + if (list.length() == 3) { + vec3.x = list[0].toUInt(); + vec3.y = list[1].toUInt(); + vec3.z = list[2].toUInt(); + } + } else { + ScriptValuePointer x = object->property("x"); + if (!x->isValid()) { + x = object->property("r"); + } + if (!x->isValid()) { + x = object->property("red"); + } + + ScriptValuePointer y = object->property("y"); + if (!y->isValid()) { + y = object->property("g"); + } + if (!y->isValid()) { + y = object->property("green"); + } + + ScriptValuePointer z = object->property("z"); + if (!z->isValid()) { + z = object->property("b"); + } + if (!z->isValid()) { + z = object->property("blue"); + } + + vec3.x = x->toVariant().toUInt(); + vec3.y = y->toVariant().toUInt(); + vec3.z = z->toVariant().toUInt(); + } +} + +ScriptValuePointer vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("x", vec4.x); + obj->setProperty("y", vec4.y); + obj->setProperty("z", vec4.z); + obj->setProperty("w", vec4.w); + return obj; +} + +void vec4FromScriptValue(const ScriptValuePointer& object, glm::vec4& vec4) { + vec4.x = object->property("x")->toVariant().toFloat(); + vec4.y = object->property("y")->toVariant().toFloat(); + vec4.z = object->property("z")->toVariant().toFloat(); + vec4.w = object->property("w")->toVariant().toFloat(); +} + +ScriptValuePointer mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("r0c0", mat4[0][0]); + obj->setProperty("r1c0", mat4[0][1]); + obj->setProperty("r2c0", mat4[0][2]); + obj->setProperty("r3c0", mat4[0][3]); + obj->setProperty("r0c1", mat4[1][0]); + obj->setProperty("r1c1", mat4[1][1]); + obj->setProperty("r2c1", mat4[1][2]); + obj->setProperty("r3c1", mat4[1][3]); + obj->setProperty("r0c2", mat4[2][0]); + obj->setProperty("r1c2", mat4[2][1]); + obj->setProperty("r2c2", mat4[2][2]); + obj->setProperty("r3c2", mat4[2][3]); + obj->setProperty("r0c3", mat4[3][0]); + obj->setProperty("r1c3", mat4[3][1]); + obj->setProperty("r2c3", mat4[3][2]); + obj->setProperty("r3c3", mat4[3][3]); + return obj; +} + +void mat4FromScriptValue(const ScriptValuePointer& object, glm::mat4& mat4) { + mat4[0][0] = object->property("r0c0")->toVariant().toFloat(); + mat4[0][1] = object->property("r1c0")->toVariant().toFloat(); + mat4[0][2] = object->property("r2c0")->toVariant().toFloat(); + mat4[0][3] = object->property("r3c0")->toVariant().toFloat(); + mat4[1][0] = object->property("r0c1")->toVariant().toFloat(); + mat4[1][1] = object->property("r1c1")->toVariant().toFloat(); + mat4[1][2] = object->property("r2c1")->toVariant().toFloat(); + mat4[1][3] = object->property("r3c1")->toVariant().toFloat(); + mat4[2][0] = object->property("r0c2")->toVariant().toFloat(); + mat4[2][1] = object->property("r1c2")->toVariant().toFloat(); + mat4[2][2] = object->property("r2c2")->toVariant().toFloat(); + mat4[2][3] = object->property("r3c2")->toVariant().toFloat(); + mat4[3][0] = object->property("r0c3")->toVariant().toFloat(); + mat4[3][1] = object->property("r1c3")->toVariant().toFloat(); + mat4[3][2] = object->property("r2c3")->toVariant().toFloat(); + mat4[3][3] = object->property("r3c3")->toVariant().toFloat(); +} + +ScriptValuePointer qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValuePointer array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array->setProperty(i, vec3ColorToScriptValue(engine, vector.at(i))); + } + return array; +} + +ScriptValuePointer qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValuePointer array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array->setProperty(i, vec3ToScriptValue(engine, vector.at(i))); + } + return array; +} + +QVector qVectorVec3FromScriptValue(const ScriptValuePointer& array) { + QVector newVector; + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + glm::vec3 newVec3 = glm::vec3(); + vec3FromScriptValue(array->property(i), newVec3); + newVector << newVec3; + } + return newVector; +} + +void qVectorVec3FromScriptValue(const ScriptValuePointer& array, QVector& vector) { + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + glm::vec3 newVec3 = glm::vec3(); + vec3FromScriptValue(array->property(i), newVec3); + vector << newVec3; + } +} + +ScriptValuePointer quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) { + ScriptValuePointer obj = engine->newObject(); + if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) { + // if quat contains a NaN don't try to convert it + return obj; + } + obj->setProperty("x", quat.x); + obj->setProperty("y", quat.y); + obj->setProperty("z", quat.z); + obj->setProperty("w", quat.w); + return obj; +} + +void quatFromScriptValue(const ScriptValuePointer& object, glm::quat& quat) { + quat.x = object->property("x")->toVariant().toFloat(); + quat.y = object->property("y")->toVariant().toFloat(); + quat.z = object->property("z")->toVariant().toFloat(); + quat.w = object->property("w")->toVariant().toFloat(); + + // enforce normalized quaternion + float length = glm::length(quat); + if (length > FLT_EPSILON) { + quat /= length; + } else { + quat = glm::quat(); + } +} + +ScriptValuePointer qVectorQuatToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValuePointer array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array->setProperty(i, quatToScriptValue(engine, vector.at(i))); + } + return array; +} + +ScriptValuePointer qVectorBoolToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValuePointer array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array->setProperty(i, vector.at(i)); + } + return array; +} + +QVector qVectorFloatFromScriptValue(const ScriptValuePointer& array) { + if (!array->isArray()) { + return QVector(); + } + QVector newVector; + int length = array->property("length")->toInteger(); + newVector.reserve(length); + for (int i = 0; i < length; i++) { + if (array->property(i)->isNumber()) { + newVector << array->property(i)->toNumber(); + } + } + + return newVector; +} + +ScriptValuePointer qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValuePointer array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array->setProperty(i, quuidToScriptValue(engine, vector.at(i))); + } + return array; +} + +void qVectorQUuidFromScriptValue(const ScriptValuePointer& array, QVector& vector) { + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + vector << array->property(i)->toVariant().toUuid(); + } +} + +QVector qVectorQUuidFromScriptValue(const ScriptValuePointer& array) { + if (!array->isArray()) { + return QVector(); + } + QVector newVector; + int length = array->property("length")->toInteger(); + newVector.reserve(length); + for (int i = 0; i < length; i++) { + QString uuidAsString = array->property(i)->toString(); + QUuid fromString(uuidAsString); + newVector << fromString; + } + return newVector; +} + +ScriptValuePointer qVectorFloatToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValuePointer array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + float num = vector.at(i); + array->setProperty(i, engine->newValue(num)); + } + return array; +} + +ScriptValuePointer qVectorIntToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValuePointer array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + int num = vector.at(i); + array->setProperty(i, engine->newValue(num)); + } + return array; +} + +void qVectorFloatFromScriptValue(const ScriptValuePointer& array, QVector& vector) { + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + vector << array->property(i)->toVariant().toFloat(); + } +} + +void qVectorIntFromScriptValue(const ScriptValuePointer& array, QVector& vector) { + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + vector << array->property(i)->toVariant().toInt(); + } +} + +QVector qVectorQuatFromScriptValue(const ScriptValuePointer& array) { + QVector newVector; + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + glm::quat newQuat = glm::quat(); + quatFromScriptValue(array->property(i), newQuat); + newVector << newQuat; + } + return newVector; +} + +void qVectorQuatFromScriptValue(const ScriptValuePointer& array, QVector& vector) { + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + glm::quat newQuat = glm::quat(); + quatFromScriptValue(array->property(i), newQuat); + vector << newQuat; + } +} + +QVector qVectorBoolFromScriptValue(const ScriptValuePointer& array) { + QVector newVector; + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + newVector << array->property(i)->toBool(); + } + return newVector; +} + +void qVectorBoolFromScriptValue(const ScriptValuePointer& array, QVector& vector) { + int length = array->property("length")->toInteger(); + + for (int i = 0; i < length; i++) { + vector << array->property(i)->toBool(); + } +} + +ScriptValuePointer qRectToScriptValue(ScriptEngine* engine, const QRect& rect) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("x", rect.x()); + obj->setProperty("y", rect.y()); + obj->setProperty("width", rect.width()); + obj->setProperty("height", rect.height()); + return obj; +} + +void qRectFromScriptValue(const ScriptValuePointer& object, QRect& rect) { + rect.setX(object->property("x")->toVariant().toInt()); + rect.setY(object->property("y")->toVariant().toInt()); + rect.setWidth(object->property("width")->toVariant().toInt()); + rect.setHeight(object->property("height")->toVariant().toInt()); +} + +ScriptValuePointer qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("x", rect.x()); + obj->setProperty("y", rect.y()); + obj->setProperty("width", rect.width()); + obj->setProperty("height", rect.height()); + return obj; +} + +void qRectFFromScriptValue(const ScriptValuePointer& object, QRectF& rect) { + rect.setX(object->property("x")->toVariant().toFloat()); + rect.setY(object->property("y")->toVariant().toFloat()); + rect.setWidth(object->property("width")->toVariant().toFloat()); + rect.setHeight(object->property("height")->toVariant().toFloat()); +} + +ScriptValuePointer qColorToScriptValue(ScriptEngine* engine, const QColor& color) { + ScriptValuePointer object = engine->newObject(); + object->setProperty("red", color.red()); + object->setProperty("green", color.green()); + object->setProperty("blue", color.blue()); + object->setProperty("alpha", color.alpha()); + return object; +} + +/**jsdoc + * An axis-aligned cube, defined as the bottom right near (minimum axes values) corner of the cube plus the dimension of its + * sides. + * @typedef {object} AACube + * @property {number} x - X coordinate of the brn corner of the cube. + * @property {number} y - Y coordinate of the brn corner of the cube. + * @property {number} z - Z coordinate of the brn corner of the cube. + * @property {number} scale - The dimensions of each side of the cube. + */ +ScriptValuePointer aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube) { + ScriptValuePointer obj = engine->newObject(); + const glm::vec3& corner = aaCube.getCorner(); + obj->setProperty("x", corner.x); + obj->setProperty("y", corner.y); + obj->setProperty("z", corner.z); + obj->setProperty("scale", aaCube.getScale()); + return obj; +} + +void aaCubeFromScriptValue(const ScriptValuePointer& object, AACube& aaCube) { + glm::vec3 corner; + corner.x = object->property("x")->toVariant().toFloat(); + corner.y = object->property("y")->toVariant().toFloat(); + corner.z = object->property("z")->toVariant().toFloat(); + float scale = object->property("scale")->toVariant().toFloat(); + + aaCube.setBox(corner, scale); +} + +void qColorFromScriptValue(const ScriptValuePointer& object, QColor& color) { + if (object->isNumber()) { + color.setRgb(object->toUInt32()); + + } else if (object->isString()) { + color.setNamedColor(object->toString()); + + } else { + ScriptValuePointer alphaValue = object->property("alpha"); + color.setRgb(object->property("red")->toInt32(), object->property("green")->toInt32(), object->property("blue")->toInt32(), + alphaValue->isNumber() ? alphaValue->toInt32() : 255); + } +} + +ScriptValuePointer qURLToScriptValue(ScriptEngine* engine, const QUrl& url) { + return engine->newValue(url.toString()); +} + +void qURLFromScriptValue(const ScriptValuePointer& object, QUrl& url) { + url = object->toString(); +} + +ScriptValuePointer pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay) { + ScriptValuePointer obj = engine->newObject(); + ScriptValuePointer origin = vec3ToScriptValue(engine, pickRay.origin); + obj->setProperty("origin", origin); + ScriptValuePointer direction = vec3ToScriptValue(engine, pickRay.direction); + obj->setProperty("direction", direction); + return obj; +} + +void pickRayFromScriptValue(const ScriptValuePointer& object, PickRay& pickRay) { + ScriptValuePointer originValue = object->property("origin"); + if (originValue->isValid()) { + auto x = originValue->property("x"); + auto y = originValue->property("y"); + auto z = originValue->property("z"); + if (x->isValid() && y->isValid() && z->isValid()) { + pickRay.origin.x = x->toVariant().toFloat(); + pickRay.origin.y = y->toVariant().toFloat(); + pickRay.origin.z = z->toVariant().toFloat(); + } + } + ScriptValuePointer directionValue = object->property("direction"); + if (directionValue->isValid()) { + auto x = directionValue->property("x"); + auto y = directionValue->property("y"); + auto z = directionValue->property("z"); + if (x->isValid() && y->isValid() && z->isValid()) { + pickRay.direction.x = x->toVariant().toFloat(); + pickRay.direction.y = y->toVariant().toFloat(); + pickRay.direction.z = z->toVariant().toFloat(); + } + } +} + +/**jsdoc + * Details of a collision between avatars and entities. + * @typedef {object} Collision + * @property {ContactEventType} type - The contact type of the collision event. + * @property {Uuid} idA - The ID of one of the avatars or entities in the collision. + * @property {Uuid} idB - The ID of the other of the avatars or entities in the collision. + * @property {Vec3} penetration - The amount of penetration between the two items. + * @property {Vec3} contactPoint - The point of contact. + * @property {Vec3} velocityChange - The change in relative velocity of the two items, in m/s. + */ +ScriptValuePointer collisionToScriptValue(ScriptEngine* engine, const Collision& collision) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("type", collision.type); + obj->setProperty("idA", quuidToScriptValue(engine, collision.idA)); + obj->setProperty("idB", quuidToScriptValue(engine, collision.idB)); + obj->setProperty("penetration", vec3ToScriptValue(engine, collision.penetration)); + obj->setProperty("contactPoint", vec3ToScriptValue(engine, collision.contactPoint)); + obj->setProperty("velocityChange", vec3ToScriptValue(engine, collision.velocityChange)); + return obj; +} + +void collisionFromScriptValue(const ScriptValuePointer& object, Collision& collision) { + // TODO: implement this when we know what it means to accept collision events from JS +} + +ScriptValuePointer quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid) { + if (uuid.isNull()) { + return engine->nullValue(); + } + ScriptValuePointer obj(engine->newValue(uuid.toString())); + return obj; +} + +void quuidFromScriptValue(const ScriptValuePointer& object, QUuid& uuid) { + if (object.isNull()) { + uuid = QUuid(); + return; + } + QString uuidAsString = object->toVariant().toString(); + QUuid fromString(uuidAsString); + uuid = fromString; +} + +/**jsdoc + * A 2D size value. + * @typedef {object} Size + * @property {number} height - The height value. + * @property {number} width - The width value. + */ +ScriptValuePointer qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("width", qSizeF.width()); + obj->setProperty("height", qSizeF.height()); + return obj; +} + +void qSizeFFromScriptValue(const ScriptValuePointer& object, QSizeF& qSizeF) { + qSizeF.setWidth(object->property("width")->toVariant().toFloat()); + qSizeF.setHeight(object->property("height")->toVariant().toFloat()); +} + +/**jsdoc + * The details of an animation that is playing. + * @typedef {object} Avatar.AnimationDetails + * @property {string} role - Not used. + * @property {string} url - The URL to the animation file. Animation files need to be in glTF or FBX format but only need to + * contain the avatar skeleton and animation data. glTF models may be in JSON or binary format (".gltf" or ".glb" URLs + * respectively). + *

Warning: glTF animations currently do not always animate correctly.

+ * @property {number} fps - The frames per second(FPS) rate for the animation playback. 30 FPS is normal speed. + * @property {number} priority - Not used. + * @property {boolean} loop - true if the animation should loop, false if it shouldn't. + * @property {boolean} hold - Not used. + * @property {number} firstFrame - The frame the animation should start at. + * @property {number} lastFrame - The frame the animation should stop at. + * @property {boolean} running - Not used. + * @property {number} currentFrame - The current frame being played. + * @property {boolean} startAutomatically - Not used. + * @property {boolean} allowTranslation - Not used. + */ +ScriptValuePointer animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& details) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("role", details.role); + obj->setProperty("url", details.url.toString()); + obj->setProperty("fps", details.fps); + obj->setProperty("priority", details.priority); + obj->setProperty("loop", details.loop); + obj->setProperty("hold", details.hold); + obj->setProperty("startAutomatically", details.startAutomatically); + obj->setProperty("firstFrame", details.firstFrame); + obj->setProperty("lastFrame", details.lastFrame); + obj->setProperty("running", details.running); + obj->setProperty("currentFrame", details.currentFrame); + obj->setProperty("allowTranslation", details.allowTranslation); + return obj; +} + +void animationDetailsFromScriptValue(const ScriptValuePointer& object, AnimationDetails& details) { + // nothing for now... +} + +ScriptValuePointer meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in) { + return engine->newQObject(in, ScriptEngine::QtOwnership, + ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); +} + +void meshFromScriptValue(const ScriptValuePointer& value, MeshProxy*& out) { + out = qobject_cast(value->toQObject()); +} + +ScriptValuePointer meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in) { + // ScriptValueList result; + ScriptValuePointer result = engine->newArray(); + int i = 0; + foreach (MeshProxy* const meshProxy, in) { result->setProperty(i++, meshToScriptValue(engine, meshProxy)); } + return result; +} + +void meshesFromScriptValue(const ScriptValuePointer& value, MeshProxyList& out) { + ScriptValueIteratorPointer itr(value->newIterator()); + + qDebug() << "in meshesFromScriptValue, value.length =" << value->property("length")->toInt32(); + + while (itr->hasNext()) { + itr->next(); + MeshProxy* meshProxy = scriptvalue_cast(itr->value()); + if (meshProxy) { + out.append(meshProxy); + } else { + qDebug() << "null meshProxy"; + } + } +} + +/**jsdoc + * A triangle in a mesh. + * @typedef {object} MeshFace + * @property {number[]} vertices - The indexes of the three vertices that make up the face. + */ +ScriptValuePointer meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices)); + return obj; +} + +void meshFaceFromScriptValue(const ScriptValuePointer& object, MeshFace& meshFaceResult) { + qVectorIntFromScriptValue(object->property("vertices"), meshFaceResult.vertexIndices); +} + +ScriptValuePointer qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValuePointer array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array->setProperty(i, meshFaceToScriptValue(engine, vector.at(i))); + } + return array; +} + +void qVectorMeshFaceFromScriptValue(const ScriptValuePointer& array, QVector& result) { + int length = array->property("length")->toInteger(); + result.clear(); + + for (int i = 0; i < length; i++) { + MeshFace meshFace = MeshFace(); + meshFaceFromScriptValue(array->property(i), meshFace); + result << meshFace; + } +} + +ScriptValuePointer stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode) { + return engine->newValue((int)stencilMode); +} + +void stencilMaskModeFromScriptValue(const ScriptValuePointer& object, StencilMaskMode& stencilMode) { + stencilMode = StencilMaskMode(object->toVariant().toInt()); +} + +void promiseFromScriptValue(const ScriptValuePointer& object, std::shared_ptr& promise) { + Q_ASSERT(false); +} +ScriptValuePointer promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise) { + return engine->newQObject(promise.get()); +} diff --git a/libraries/script-engine/src/ScriptValueUtils.h b/libraries/script-engine/src/ScriptValueUtils.h new file mode 100644 index 00000000000..f387f6c6d1e --- /dev/null +++ b/libraries/script-engine/src/ScriptValueUtils.h @@ -0,0 +1,262 @@ +// +// ScriptValueUtils.h +// libraries/shared/src +// +// Created by Anthony Thibault on 4/15/16. +// Copyright 2016 High Fidelity, Inc. +// +// Utilities for working with QtScriptValues +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptValueUtils_h +#define hifi_ScriptValueUtils_h + +#include + +#include +#include + +#include "ScriptValue.h" + +bool isListOfStrings(const ScriptValuePointer& value); + + +void registerMetaTypes(ScriptEngine* engine); + +// Mat4 +/**jsdoc + * A 4 x 4 matrix, typically containing a scale, rotation, and translation transform. See also the {@link Mat4(0)|Mat4} object. + * + * @typedef {object} Mat4 + * @property {number} r0c0 - Row 0, column 0 value. + * @property {number} r1c0 - Row 1, column 0 value. + * @property {number} r2c0 - Row 2, column 0 value. + * @property {number} r3c0 - Row 3, column 0 value. + * @property {number} r0c1 - Row 0, column 1 value. + * @property {number} r1c1 - Row 1, column 1 value. + * @property {number} r2c1 - Row 2, column 1 value. + * @property {number} r3c1 - Row 3, column 1 value. + * @property {number} r0c2 - Row 0, column 2 value. + * @property {number} r1c2 - Row 1, column 2 value. + * @property {number} r2c2 - Row 2, column 2 value. + * @property {number} r3c2 - Row 3, column 2 value. + * @property {number} r0c3 - Row 0, column 3 value. + * @property {number} r1c3 - Row 1, column 3 value. + * @property {number} r2c3 - Row 2, column 3 value. + * @property {number} r3c3 - Row 3, column 3 value. + */ +ScriptValuePointer mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4); +void mat4FromScriptValue(const ScriptValuePointer& object, glm::mat4& mat4); + +/**jsdoc +* A 2-dimensional vector. +* +* @typedef {object} Vec2 +* @property {number} x - X-coordinate of the vector. Synonyms: u. +* @property {number} y - Y-coordinate of the vector. Synonyms: v. +* @example Vec2s can be set in multiple ways and modified with their aliases, but still stringify in the same way +* Entities.editEntity(, { materialMappingPos: { x: 0.1, y: 0.2 }}); // { x: 0.1, y: 0.2 } +* Entities.editEntity(, { materialMappingPos: { u: 0.3, v: 0.4 }}); // { x: 0.3, y: 0.4 } +* Entities.editEntity(, { materialMappingPos: [0.5, 0.6] }); // { x: 0.5, y: 0.6 } +* Entities.editEntity(, { materialMappingPos: 0.7 }); // { x: 0.7, y: 0.7 } +* var color = Entities.getEntityProperties().materialMappingPos; // { x: 0.7, y: 0.7 } +* color.v = 0.8; // { x: 0.7, y: 0.8 } +*/ +ScriptValuePointer vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2); +void vec2FromScriptValue(const ScriptValuePointer& object, glm::vec2& vec2); + +/**jsdoc +* A 3-dimensional vector. See also the {@link Vec3(0)|Vec3} object. +* +* @typedef {object} Vec3 +* @property {number} x - X-coordinate of the vector. Synonyms: r, red. +* @property {number} y - Y-coordinate of the vector. Synonyms: g, green. +* @property {number} z - Z-coordinate of the vector. Synonyms: b, blue. +* @example Vec3 values can be set in multiple ways and modified with their aliases, but still stringify in the same +* way. +* Entities.editEntity(, { position: { x: 1, y: 2, z: 3 }}); // { x: 1, y: 2, z: 3 } +* Entities.editEntity(, { position: { r: 4, g: 5, b: 6 }}); // { x: 4, y: 5, z: 6 } +* Entities.editEntity(, { position: { red: 7, green: 8, blue: 9 }}); // { x: 7, y: 8, z: 9 } +* Entities.editEntity(, { position: [10, 11, 12] }); // { x: 10, y: 11, z: 12 } +* Entities.editEntity(, { position: 13 }); // { x: 13, y: 13, z: 13 } +* var position = Entities.getEntityProperties().position; // { x: 13, y: 13, z: 13 } +* position.g = 14; // { x: 13, y: 14, z: 13 } +* position.blue = 15; // { x: 13, y: 14, z: 15 } +* Entities.editEntity(, { position: "red"}); // { x: 255, y: 0, z: 0 } +* Entities.editEntity(, { position: "#00FF00"}); // { x: 0, y: 255, z: 0 } +*/ +ScriptValuePointer vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3); +ScriptValuePointer vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3); +void vec3FromScriptValue(const ScriptValuePointer& object, glm::vec3& vec3); + +/**jsdoc + * A color vector. See also the {@link Vec3(0)|Vec3} object. + * + * @typedef {object} Color + * @property {number} red - Red component value. Integer in the range 0 - 255. Synonyms: r, x. + * @property {number} green - Green component value. Integer in the range 0 - 255. Synonyms: g, y. + * @property {number} blue - Blue component value. Integer in the range 0 - 255. Synonyms: b, z. + * @example Colors can be set in multiple ways and modified with their aliases, but still stringify in the same way + * Entities.editEntity(, { color: { x: 1, y: 2, z: 3 }}); // { red: 1, green: 2, blue: 3 } + * Entities.editEntity(, { color: { r: 4, g: 5, b: 6 }}); // { red: 4, green: 5, blue: 6 } + * Entities.editEntity(, { color: { red: 7, green: 8, blue: 9 }}); // { red: 7, green: 8, blue: 9 } + * Entities.editEntity(, { color: [10, 11, 12] }); // { red: 10, green: 11, blue: 12 } + * Entities.editEntity(, { color: 13 }); // { red: 13, green: 13, blue: 13 } + * var color = Entities.getEntityProperties().color; // { red: 13, green: 13, blue: 13 } + * color.g = 14; // { red: 13, green: 14, blue: 13 } + * color.blue = 15; // { red: 13, green: 14, blue: 15 } + * Entities.editEntity(, { color: "red"}); // { red: 255, green: 0, blue: 0 } + * Entities.editEntity(, { color: "#00FF00"}); // { red: 0, green: 255, blue: 0 } + */ +/**jsdoc + * A color vector with real values. Values may also be null. See also the {@link Vec3(0)|Vec3} object. + * + * @typedef {object} ColorFloat + * @property {number} red - Red component value. Real in the range 0 - 255. Synonyms: r, x. + * @property {number} green - Green component value. Real in the range 0 - 255. Synonyms: g, y. + * @property {number} blue - Blue component value. Real in the range 0 - 255. Synonyms: b, z. + * @example ColorFloats can be set in multiple ways and modified with their aliases, but still stringify in the same way + * Entities.editEntity(, { color: { x: 1, y: 2, z: 3 }}); // { red: 1, green: 2, blue: 3 } + * Entities.editEntity(, { color: { r: 4, g: 5, b: 6 }}); // { red: 4, green: 5, blue: 6 } + * Entities.editEntity(, { color: { red: 7, green: 8, blue: 9 }}); // { red: 7, green: 8, blue: 9 } + * Entities.editEntity(, { color: [10, 11, 12] }); // { red: 10, green: 11, blue: 12 } + * Entities.editEntity(, { color: 13 }); // { red: 13, green: 13, blue: 13 } + * var color = Entities.getEntityProperties().color; // { red: 13, green: 13, blue: 13 } + * color.g = 14; // { red: 13, green: 14, blue: 13 } + * color.blue = 15; // { red: 13, green: 14, blue: 15 } + * Entities.editEntity(, { color: "red"}); // { red: 255, green: 0, blue: 0 } + * Entities.editEntity(, { color: "#00FF00"}); // { red: 0, green: 255, blue: 0 } + */ +ScriptValuePointer u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3); +ScriptValuePointer u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3); +void u8vec3FromScriptValue(const ScriptValuePointer& object, glm::u8vec3& vec3); + +/**jsdoc + * A 4-dimensional vector. + * + * @typedef {object} Vec4 + * @property {number} x - X-coordinate of the vector. + * @property {number} y - Y-coordinate of the vector. + * @property {number} z - Z-coordinate of the vector. + * @property {number} w - W-coordinate of the vector. + */ +ScriptValuePointer vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4); +void vec4FromScriptValue(const ScriptValuePointer& object, glm::vec4& vec4); + +// Quaternions +ScriptValuePointer quatToScriptValue(ScriptEngine* engine, const glm::quat& quat); +void quatFromScriptValue(const ScriptValuePointer& object, glm::quat& quat); + +/**jsdoc + * Defines a rectangular portion of an image or screen, or similar. + * @typedef {object} Rect + * @property {number} x - Left, x-coordinate value. + * @property {number} y - Top, y-coordinate value. + * @property {number} width - Width of the rectangle. + * @property {number} height - Height of the rectangle. + */ +class QRect; +ScriptValuePointer qRectToScriptValue(ScriptEngine* engine, const QRect& rect); +void qRectFromScriptValue(const ScriptValuePointer& object, QRect& rect); + +class QRectF; +ScriptValuePointer qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect); +void qRectFFromScriptValue(const ScriptValuePointer& object, QRectF& rect); + +// QColor +class QColor; +ScriptValuePointer qColorToScriptValue(ScriptEngine* engine, const QColor& color); +void qColorFromScriptValue(const ScriptValuePointer& object, QColor& color); + +class QUrl; +ScriptValuePointer qURLToScriptValue(ScriptEngine* engine, const QUrl& url); +void qURLFromScriptValue(const ScriptValuePointer& object, QUrl& url); + +// vector +Q_DECLARE_METATYPE(QVector) +ScriptValuePointer qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector& vector); +ScriptValuePointer qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorVec3FromScriptValue(const ScriptValuePointer& array, QVector& vector); +QVector qVectorVec3FromScriptValue(const ScriptValuePointer& array); + +// vector +Q_DECLARE_METATYPE(QVector) +ScriptValuePointer qVectorQuatToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorQuatFromScriptValue(const ScriptValuePointer& array, QVector& vector); +QVector qVectorQuatFromScriptValue(const ScriptValuePointer& array); + +// vector +ScriptValuePointer qVectorBoolToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorBoolFromScriptValue(const ScriptValuePointer& array, QVector& vector); +QVector qVectorBoolFromScriptValue(const ScriptValuePointer& array); + +// vector +ScriptValuePointer qVectorFloatToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorFloatFromScriptValue(const ScriptValuePointer& array, QVector& vector); +QVector qVectorFloatFromScriptValue(const ScriptValuePointer& array); + +// vector +ScriptValuePointer qVectorIntToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorIntFromScriptValue(const ScriptValuePointer& array, QVector& vector); + +ScriptValuePointer qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorQUuidFromScriptValue(const ScriptValuePointer& array, QVector& vector); +QVector qVectorQUuidFromScriptValue(const ScriptValuePointer& array); + +class AACube; +ScriptValuePointer aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube); +void aaCubeFromScriptValue(const ScriptValuePointer& object, AACube& aaCube); + +class PickRay; +ScriptValuePointer pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay); +void pickRayFromScriptValue(const ScriptValuePointer& object, PickRay& pickRay); + +class Collision; +ScriptValuePointer collisionToScriptValue(ScriptEngine* engine, const Collision& collision); +void collisionFromScriptValue(const ScriptValuePointer& object, Collision& collision); + +/**jsdoc + * UUIDs (Universally Unique IDentifiers) are used to uniquely identify entities, avatars, and the like. They are represented + * in JavaScript as strings in the format, "{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}", where the "n"s are + * hexadecimal digits. + * @typedef {string} Uuid + */ +//Q_DECLARE_METATYPE(QUuid) // don't need to do this for QUuid since it's already a meta type +ScriptValuePointer quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid); +void quuidFromScriptValue(const ScriptValuePointer& object, QUuid& uuid); + +//Q_DECLARE_METATYPE(QSizeF) // Don't need to to this becase it's arleady a meta type +class QSizeF; +ScriptValuePointer qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF); +void qSizeFFromScriptValue(const ScriptValuePointer& object, QSizeF& qSizeF); + +class AnimationDetails; +ScriptValuePointer animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& event); +void animationDetailsFromScriptValue(const ScriptValuePointer& object, AnimationDetails& event); + +class MeshProxy; +ScriptValuePointer meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in); +void meshFromScriptValue(const ScriptValuePointer& value, MeshProxy*& out); + +class MeshProxyList; +ScriptValuePointer meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in); +void meshesFromScriptValue(const ScriptValuePointer& value, MeshProxyList& out); + +class MeshFace; +ScriptValuePointer meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace); +void meshFaceFromScriptValue(const ScriptValuePointer& object, MeshFace& meshFaceResult); +ScriptValuePointer qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorMeshFaceFromScriptValue(const ScriptValuePointer& array, QVector& result); + +enum class StencilMaskMode; +ScriptValuePointer stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode); +void stencilMaskModeFromScriptValue(const ScriptValuePointer& object, StencilMaskMode& stencilMode); + +class MiniPromise; +void promiseFromScriptValue(const ScriptValuePointer& object, std::shared_ptr& promise); +ScriptValuePointer promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise); + +#endif // #define hifi_ScriptValueUtils_h diff --git a/libraries/script-engine/src/Scriptable.h b/libraries/script-engine/src/Scriptable.h new file mode 100644 index 00000000000..b6d08a2bfe8 --- /dev/null +++ b/libraries/script-engine/src/Scriptable.h @@ -0,0 +1,59 @@ +// +// Scriptable.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/1/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_Scriptable_h +#define hifi_Scriptable_h + +#include + +#include "ScriptContext.h" + +class ScriptEngine; +class ScriptValue; +using ScriptEnginePointer = QSharedPointer; +using ScriptValuePointer = QSharedPointer; + +class Scriptable { +public: + static inline ScriptEnginePointer engine(); + static ScriptContext* context(); + static inline ScriptValuePointer thisObject(); + static inline int argumentCount(); + static inline ScriptValuePointer argument(int index); + + static void setContext(ScriptContext* context); +}; + +ScriptEnginePointer Scriptable::engine() { + ScriptContext* scriptContext = context(); + if (!scriptContext) return nullptr; + return scriptContext->engine(); +} + +ScriptValuePointer Scriptable::thisObject() { + ScriptContext* scriptContext = context(); + if (!scriptContext) return nullptr; + return scriptContext->thisObject(); +} + +int Scriptable::argumentCount() { + ScriptContext* scriptContext = context(); + if (!scriptContext) return 0; + return scriptContext->argumentCount(); +} + +ScriptValuePointer Scriptable::argument(int index) { + ScriptContext* scriptContext = context(); + if (!scriptContext) return ScriptValuePointer(); + return scriptContext->argument(index); +} + +#endif // hifi_Scriptable_h \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptsModel.h b/libraries/script-engine/src/ScriptsModel.h index 0721600efc4..a55ae7163e9 100644 --- a/libraries/script-engine/src/ScriptsModel.h +++ b/libraries/script-engine/src/ScriptsModel.h @@ -16,8 +16,11 @@ #include #include #include +#include class TreeNodeFolder; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; enum ScriptOrigin { SCRIPT_ORIGIN_LOCAL, @@ -140,10 +143,10 @@ class ScriptsModel : public QAbstractItemModel { // No JSDoc because the particulars of the parent class is provided in the @class description. int columnCount(const QModelIndex& parent = QModelIndex()) const override; - // Not exposed in the API because no conversion between TreeNodeBase and QScriptValue is provided. + // Not exposed in the API because no conversion between TreeNodeBase and ScriptValuePointer is provided. TreeNodeBase* getTreeNodeFromIndex(const QModelIndex& index) const; - // Not exposed in the API because no conversion between TreeNodeBase and QScriptValue is provided. + // Not exposed in the API because no conversion between TreeNodeBase and ScriptValuePointer is provided. QList getFolderNodes(TreeNodeFolder* parent) const; enum Role { diff --git a/libraries/script-engine/src/SpatialEvent.cpp b/libraries/script-engine/src/SpatialEvent.cpp index 8520c0c485b..0c5d96db45b 100644 --- a/libraries/script-engine/src/SpatialEvent.cpp +++ b/libraries/script-engine/src/SpatialEvent.cpp @@ -12,6 +12,9 @@ #include "SpatialEvent.h" #include +#include "ScriptEngine.h" +#include "ScriptValueUtils.h" +#include "ScriptValue.h" SpatialEvent::SpatialEvent() : locTranslation(0.0f), @@ -30,17 +33,17 @@ SpatialEvent::SpatialEvent(const SpatialEvent& event) { } -QScriptValue SpatialEvent::toScriptValue(QScriptEngine* engine, const SpatialEvent& event) { - QScriptValue obj = engine->newObject(); +ScriptValuePointer SpatialEvent::toScriptValue(ScriptEngine* engine, const SpatialEvent& event) { + ScriptValuePointer obj = engine->newObject(); - obj.setProperty("locTranslation", vec3ToScriptValue(engine, event.locTranslation) ); - obj.setProperty("locRotation", quatToScriptValue(engine, event.locRotation) ); - obj.setProperty("absTranslation", vec3ToScriptValue(engine, event.absTranslation) ); - obj.setProperty("absRotation", quatToScriptValue(engine, event.absRotation) ); + obj->setProperty("locTranslation", vec3ToScriptValue(engine, event.locTranslation) ); + obj->setProperty("locRotation", quatToScriptValue(engine, event.locRotation) ); + obj->setProperty("absTranslation", vec3ToScriptValue(engine, event.absTranslation)); + obj->setProperty("absRotation", quatToScriptValue(engine, event.absRotation)); return obj; } -void SpatialEvent::fromScriptValue(const QScriptValue& object,SpatialEvent& event) { +void SpatialEvent::fromScriptValue(const ScriptValuePointer& object,SpatialEvent& event) { // nothing for now... } diff --git a/libraries/script-engine/src/SpatialEvent.h b/libraries/script-engine/src/SpatialEvent.h index 9063e487969..a43b97b5242 100644 --- a/libraries/script-engine/src/SpatialEvent.h +++ b/libraries/script-engine/src/SpatialEvent.h @@ -14,16 +14,19 @@ #include #include +#include -#include +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class SpatialEvent { public: SpatialEvent(); SpatialEvent(const SpatialEvent& other); - static QScriptValue toScriptValue(QScriptEngine* engine, const SpatialEvent& event); - static void fromScriptValue(const QScriptValue& object, SpatialEvent& event); + static ScriptValuePointer toScriptValue(ScriptEngine* engine, const SpatialEvent& event); + static void fromScriptValue(const ScriptValuePointer& object, SpatialEvent& event); glm::vec3 locTranslation; glm::quat locRotation; diff --git a/libraries/script-engine/src/TouchEvent.cpp b/libraries/script-engine/src/TouchEvent.cpp index 050fe8b0fd2..64d64226932 100644 --- a/libraries/script-engine/src/TouchEvent.cpp +++ b/libraries/script-engine/src/TouchEvent.cpp @@ -11,12 +11,12 @@ #include "TouchEvent.h" -#include -#include - #include #include "RegisteredMetaTypes.h" +#include "ScriptEngine.h" +#include "ScriptValue.h" +#include "ScriptValueUtils.h" TouchEvent::TouchEvent() : x(0.0f), @@ -204,47 +204,47 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) { * print(JSON.stringify(event)); * }); */ -QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", event.x); - obj.setProperty("y", event.y); - obj.setProperty("isPressed", event.isPressed); - obj.setProperty("isMoved", event.isMoved); - obj.setProperty("isStationary", event.isStationary); - obj.setProperty("isReleased", event.isReleased); - obj.setProperty("isShifted", event.isShifted); - obj.setProperty("isMeta", event.isMeta); - obj.setProperty("isControl", event.isControl); - obj.setProperty("isAlt", event.isAlt); - obj.setProperty("touchPoints", event.touchPoints); - - QScriptValue pointsObj = engine->newArray(); +ScriptValuePointer TouchEvent::toScriptValue(ScriptEngine* engine, const TouchEvent& event) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("x", event.x); + obj->setProperty("y", event.y); + obj->setProperty("isPressed", event.isPressed); + obj->setProperty("isMoved", event.isMoved); + obj->setProperty("isStationary", event.isStationary); + obj->setProperty("isReleased", event.isReleased); + obj->setProperty("isShifted", event.isShifted); + obj->setProperty("isMeta", event.isMeta); + obj->setProperty("isControl", event.isControl); + obj->setProperty("isAlt", event.isAlt); + obj->setProperty("touchPoints", event.touchPoints); + + ScriptValuePointer pointsObj = engine->newArray(); int index = 0; foreach (glm::vec2 point, event.points) { - QScriptValue thisPoint = vec2ToScriptValue(engine, point); - pointsObj.setProperty(index, thisPoint); + ScriptValuePointer thisPoint = vec2ToScriptValue(engine, point); + pointsObj->setProperty(index, thisPoint); index++; } - obj.setProperty("points", pointsObj); - obj.setProperty("radius", event.radius); - obj.setProperty("isPinching", event.isPinching); - obj.setProperty("isPinchOpening", event.isPinchOpening); - - obj.setProperty("angle", event.angle); - obj.setProperty("deltaAngle", event.deltaAngle); - QScriptValue anglesObj = engine->newArray(); + obj->setProperty("points", pointsObj); + obj->setProperty("radius", event.radius); + obj->setProperty("isPinching", event.isPinching); + obj->setProperty("isPinchOpening", event.isPinchOpening); + + obj->setProperty("angle", event.angle); + obj->setProperty("deltaAngle", event.deltaAngle); + ScriptValuePointer anglesObj = engine->newArray(); index = 0; foreach (float angle, event.angles) { - anglesObj.setProperty(index, angle); + anglesObj->setProperty(index, angle); index++; } - obj.setProperty("angles", anglesObj); + obj->setProperty("angles", anglesObj); - obj.setProperty("isRotating", event.isRotating); - obj.setProperty("rotating", event.rotating); + obj->setProperty("isRotating", event.isRotating); + obj->setProperty("rotating", event.rotating); return obj; } -void TouchEvent::fromScriptValue(const QScriptValue& object, TouchEvent& event) { +void TouchEvent::fromScriptValue(const ScriptValuePointer& object, TouchEvent& event) { // nothing for now... } diff --git a/libraries/script-engine/src/TouchEvent.h b/libraries/script-engine/src/TouchEvent.h index 62cb1b18016..e49cb71d014 100644 --- a/libraries/script-engine/src/TouchEvent.h +++ b/libraries/script-engine/src/TouchEvent.h @@ -16,9 +16,11 @@ #include #include +#include -class QScriptValue; -class QScriptEngine; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class TouchEvent { public: @@ -26,8 +28,8 @@ class TouchEvent { TouchEvent(const QTouchEvent& event); TouchEvent(const QTouchEvent& event, const TouchEvent& other); - static QScriptValue toScriptValue(QScriptEngine* engine, const TouchEvent& event); - static void fromScriptValue(const QScriptValue& object, TouchEvent& event); + static ScriptValuePointer toScriptValue(ScriptEngine* engine, const TouchEvent& event); + static void fromScriptValue(const ScriptValuePointer& object, TouchEvent& event); float x; float y; diff --git a/libraries/shared/src/VariantMapToScriptValue.cpp b/libraries/script-engine/src/VariantMapToScriptValue.cpp similarity index 61% rename from libraries/shared/src/VariantMapToScriptValue.cpp rename to libraries/script-engine/src/VariantMapToScriptValue.cpp index 156a438bd74..1b206e410d0 100644 --- a/libraries/shared/src/VariantMapToScriptValue.cpp +++ b/libraries/script-engine/src/VariantMapToScriptValue.cpp @@ -15,20 +15,20 @@ #include "SharedLogging.h" -QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) { +ScriptValuePointer variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEngine) { switch(qValue.type()) { case QVariant::Bool: - return qValue.toBool(); + return scriptEngine.newValue(qValue.toBool()); break; case QVariant::Int: - return qValue.toInt(); + return scriptEngine.newValue(qValue.toInt()); break; case QVariant::Double: - return qValue.toDouble(); + return scriptEngine.newValue(qValue.toDouble()); break; case QVariant::String: case QVariant::Url: - return qValue.toString(); + return scriptEngine.newValue(qValue.toString()); break; case QVariant::Map: { QVariantMap childMap = qValue.toMap(); @@ -42,35 +42,35 @@ QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) } default: if (qValue.canConvert()) { - return qValue.toFloat(); + return scriptEngine.newValue(qValue.toFloat()); } //qCDebug(shared) << "unhandled QScript type" << qValue.type(); break; } - return QScriptValue(); + return ScriptValuePointer(); } -QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine) { - QScriptValue scriptValue = scriptEngine.newObject(); +ScriptValuePointer variantMapToScriptValue(QVariantMap& variantMap, ScriptEngine& scriptEngine) { + ScriptValuePointer scriptValue = scriptEngine.newObject(); for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) { QString key = iter.key(); QVariant qValue = iter.value(); - scriptValue.setProperty(key, variantToScriptValue(qValue, scriptEngine)); + scriptValue->setProperty(key, variantToScriptValue(qValue, scriptEngine)); } return scriptValue; } -QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine) { +ScriptValuePointer variantListToScriptValue(QVariantList& variantList, ScriptEngine& scriptEngine) { - QScriptValue scriptValue = scriptEngine.newArray(); + ScriptValuePointer scriptValue = scriptEngine.newArray(); for (int i = 0; i < variantList.size(); i++) { - scriptValue.setProperty(i, variantToScriptValue(variantList[i], scriptEngine)); + scriptValue->setProperty(i, variantToScriptValue(variantList[i], scriptEngine)); } return scriptValue; diff --git a/libraries/script-engine/src/VariantMapToScriptValue.h b/libraries/script-engine/src/VariantMapToScriptValue.h new file mode 100644 index 00000000000..2700decedd3 --- /dev/null +++ b/libraries/script-engine/src/VariantMapToScriptValue.h @@ -0,0 +1,18 @@ +// +// VariantMapToScriptValue.h +// libraries/shared/src/ +// +// Created by Brad Hefta-Gaub on 12/6/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include "ScriptValue.h" +#include "ScriptEngine.h" + +ScriptValuePointer variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEngine); +ScriptValuePointer variantMapToScriptValue(QVariantMap& variantMap, ScriptEngine& scriptEngine); +ScriptValuePointer variantListToScriptValue(QVariantList& variantList, ScriptEngine& scriptEngine); diff --git a/libraries/script-engine/src/Vec3.cpp b/libraries/script-engine/src/Vec3.cpp index 2d3d4454c34..84df545bd2c 100644 --- a/libraries/script-engine/src/Vec3.cpp +++ b/libraries/script-engine/src/Vec3.cpp @@ -21,6 +21,7 @@ #include "NumericalConstants.h" #include "ScriptEngine.h" #include "ScriptEngineLogging.h" +#include "ScriptManager.h" float Vec3::orientedAngle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3) { @@ -32,8 +33,8 @@ void Vec3::print(const QString& label, const glm::vec3& v) { QString message = QString("%1 %2").arg(qPrintable(label)); message = message.arg(glm::to_string(glm::dvec3(v)).c_str()); qCDebug(scriptengine) << message; - if (ScriptEngine* scriptEngine = qobject_cast(engine())) { - scriptEngine->print(message); + if (ScriptManager* scriptManager = engine()->manager()) { + scriptManager->print(message); } } diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index a8a8adece35..1882dece19c 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -17,9 +17,9 @@ #include #include -#include #include "GLMHelpers.h" +#include "Scriptable.h" /**jsdoc * The Vec3 API provides facilities for generating and manipulating 3-dimensional vectors. Vircadia uses a @@ -73,7 +73,7 @@ */ /// Scriptable interface a Vec3ernion helper class object. Used exclusively in the JavaScript API -class Vec3 : public QObject, protected QScriptable { +class Vec3 : public QObject, protected Scriptable { Q_OBJECT Q_PROPERTY(glm::vec3 UNIT_X READ UNIT_X CONSTANT) Q_PROPERTY(glm::vec3 UNIT_Y READ UNIT_Y CONSTANT) diff --git a/libraries/script-engine/src/WebSocketClass.cpp b/libraries/script-engine/src/WebSocketClass.cpp index 00d379aff4d..312ad2fcdf8 100644 --- a/libraries/script-engine/src/WebSocketClass.cpp +++ b/libraries/script-engine/src/WebSocketClass.cpp @@ -14,11 +14,12 @@ #include "WebSocketClass.h" +#include "ScriptContext.h" #include "ScriptEngine.h" - #include "ScriptEngineLogging.h" +#include "ScriptValue.h" -WebSocketClass::WebSocketClass(QScriptEngine* engine, QString url) : +WebSocketClass::WebSocketClass(ScriptEngine* engine, QString url) : _webSocket(new QWebSocket()), _engine(engine) { @@ -26,7 +27,7 @@ WebSocketClass::WebSocketClass(QScriptEngine* engine, QString url) : _webSocket->open(url); } -WebSocketClass::WebSocketClass(QScriptEngine* engine, QWebSocket* qWebSocket) : +WebSocketClass::WebSocketClass(ScriptEngine* engine, QWebSocket* qWebSocket) : _webSocket(qWebSocket), _engine(engine) { @@ -43,24 +44,24 @@ void WebSocketClass::initialize() { _binaryType = QStringLiteral("arraybuffer"); } -QScriptValue WebSocketClass::constructor(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer WebSocketClass::constructor(ScriptContext* context, ScriptEngine* engine) { QString url; if (context->argumentCount() > 0) { - url = context->argument(0).toString(); + url = context->argument(0)->toString(); } - return engine->newQObject(new WebSocketClass(engine, url), QScriptEngine::ScriptOwnership); + return engine->newQObject(new WebSocketClass(engine, url), ScriptEngine::ScriptOwnership); } WebSocketClass::~WebSocketClass() { _webSocket->deleteLater(); } -void WebSocketClass::send(QScriptValue message) { - if (message.isObject()) { - QByteArray ba = qscriptvalue_cast(message); +void WebSocketClass::send(ScriptValuePointer message) { + if (message->isObject()) { + QByteArray ba = scriptvalue_cast(message); _webSocket->sendBinaryMessage(ba); } else { - _webSocket->sendTextMessage(message.toString()); + _webSocket->sendTextMessage(message->toString()); } } @@ -90,14 +91,14 @@ void WebSocketClass::close(QWebSocketProtocol::CloseCode closeCode, QString reas */ void WebSocketClass::handleOnClose() { bool hasError = (_webSocket->error() != QAbstractSocket::UnknownSocketError); - if (_onCloseEvent.isFunction()) { - QScriptValueList args; - QScriptValue arg = _engine->newObject(); - arg.setProperty("code", hasError ? QWebSocketProtocol::CloseCodeAbnormalDisconnection : _webSocket->closeCode()); - arg.setProperty("reason", _webSocket->closeReason()); - arg.setProperty("wasClean", !hasError); + if (_onCloseEvent->isFunction()) { + ScriptValueList args; + ScriptValuePointer arg = _engine->newObject(); + arg->setProperty("code", hasError ? QWebSocketProtocol::CloseCodeAbnormalDisconnection : _webSocket->closeCode()); + arg->setProperty("reason", _webSocket->closeReason()); + arg->setProperty("wasClean", !hasError); args << arg; - _onCloseEvent.call(QScriptValue(), args); + _onCloseEvent->call(ScriptValuePointer(), args); } } @@ -153,8 +154,8 @@ void WebSocketClass::handleOnClose() { * @typedef {number} WebSocket.SocketError */ void WebSocketClass::handleOnError(QAbstractSocket::SocketError error) { - if (_onErrorEvent.isFunction()) { - _onErrorEvent.call(); + if (_onErrorEvent->isFunction()) { + _onErrorEvent->call(); } } @@ -169,31 +170,26 @@ void WebSocketClass::handleOnError(QAbstractSocket::SocketError error) { * @property {string} data - The message content. */ void WebSocketClass::handleOnMessage(const QString& message) { - if (_onMessageEvent.isFunction()) { - QScriptValueList args; - QScriptValue arg = _engine->newObject(); - arg.setProperty("data", message); + if (_onMessageEvent->isFunction()) { + ScriptValueList args; + ScriptValuePointer arg = _engine->newObject(); + arg->setProperty("data", message); args << arg; - _onMessageEvent.call(QScriptValue(), args); + _onMessageEvent->call(ScriptValuePointer(), args); } } void WebSocketClass::handleOnBinaryMessage(const QByteArray& message) { - if (_onMessageEvent.isFunction()) { - QScriptValueList args; - QScriptValue arg = _engine->newObject(); - QScriptValue data = _engine->newVariant(QVariant::fromValue(message)); - QScriptValue ctor = _engine->globalObject().property("ArrayBuffer"); - auto array = qscriptvalue_cast(ctor.data()); - QScriptValue arrayBuffer; - if (!array) { + if (_onMessageEvent->isFunction()) { + ScriptValueList args; + ScriptValuePointer arg = _engine->newObject(); + ScriptValuePointer arrayBuffer = _engine->newArrayBuffer(message); + if (arrayBuffer->isUndefined()) { qCWarning(scriptengine) << "WebSocketClass::handleOnBinaryMessage !ArrayBuffer"; - } else { - arrayBuffer = _engine->newObject(array, data); } - arg.setProperty("data", arrayBuffer); + arg->setProperty("data", arrayBuffer); args << arg; - _onMessageEvent.call(QScriptValue(), args); + _onMessageEvent->call(ScriptValuePointer(), args); } } @@ -202,31 +198,31 @@ void WebSocketClass::handleOnBinaryMessage(const QByteArray& message) { * @callback WebSocket~onOpenCallback */ void WebSocketClass::handleOnOpen() { - if (_onOpenEvent.isFunction()) { - _onOpenEvent.call(); + if (_onOpenEvent->isFunction()) { + _onOpenEvent->call(); } } -QScriptValue qWSCloseCodeToScriptValue(QScriptEngine* engine, const QWebSocketProtocol::CloseCode &closeCode) { - return closeCode; +ScriptValuePointer qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProtocol::CloseCode &closeCode) { + return engine->newValue(closeCode); } -void qWSCloseCodeFromScriptValue(const QScriptValue &object, QWebSocketProtocol::CloseCode &closeCode) { - closeCode = (QWebSocketProtocol::CloseCode)object.toUInt16(); +void qWSCloseCodeFromScriptValue(const ScriptValuePointer &object, QWebSocketProtocol::CloseCode &closeCode) { + closeCode = (QWebSocketProtocol::CloseCode)object->toUInt16(); } -QScriptValue webSocketToScriptValue(QScriptEngine* engine, WebSocketClass* const &in) { - return engine->newQObject(in, QScriptEngine::ScriptOwnership); +ScriptValuePointer webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in) { + return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void webSocketFromScriptValue(const QScriptValue &object, WebSocketClass* &out) { - out = qobject_cast(object.toQObject()); +void webSocketFromScriptValue(const ScriptValuePointer &object, WebSocketClass* &out) { + out = qobject_cast(object->toQObject()); } -QScriptValue wscReadyStateToScriptValue(QScriptEngine* engine, const WebSocketClass::ReadyState& readyState) { - return readyState; +ScriptValuePointer wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState) { + return engine->newValue(readyState); } -void wscReadyStateFromScriptValue(const QScriptValue& object, WebSocketClass::ReadyState& readyState) { - readyState = (WebSocketClass::ReadyState)object.toUInt16(); +void wscReadyStateFromScriptValue(const ScriptValuePointer& object, WebSocketClass::ReadyState& readyState) { + readyState = (WebSocketClass::ReadyState)object->toUInt16(); } diff --git a/libraries/script-engine/src/WebSocketClass.h b/libraries/script-engine/src/WebSocketClass.h index a3faaadbb59..aee4a2c3591 100644 --- a/libraries/script-engine/src/WebSocketClass.h +++ b/libraries/script-engine/src/WebSocketClass.h @@ -13,8 +13,13 @@ #define hifi_WebSocketClass_h #include -#include #include +#include + +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * Provides a bi-directional, event-driven communication session between the script and another WebSocket connection. It is a @@ -84,10 +89,10 @@ class WebSocketClass : public QObject { Q_PROPERTY(ulong bufferedAmount READ getBufferedAmount) Q_PROPERTY(QString extensions READ getExtensions) - Q_PROPERTY(QScriptValue onclose READ getOnClose WRITE setOnClose) - Q_PROPERTY(QScriptValue onerror READ getOnError WRITE setOnError) - Q_PROPERTY(QScriptValue onmessage READ getOnMessage WRITE setOnMessage) - Q_PROPERTY(QScriptValue onopen READ getOnOpen WRITE setOnOpen) + Q_PROPERTY(ScriptValuePointer onclose READ getOnClose WRITE setOnClose) + Q_PROPERTY(ScriptValuePointer onerror READ getOnError WRITE setOnError) + Q_PROPERTY(ScriptValuePointer onmessage READ getOnMessage WRITE setOnMessage) + Q_PROPERTY(ScriptValuePointer onopen READ getOnOpen WRITE setOnOpen) Q_PROPERTY(QString protocol READ getProtocol) Q_PROPERTY(WebSocketClass::ReadyState readyState READ getReadyState) @@ -99,11 +104,11 @@ class WebSocketClass : public QObject { Q_PROPERTY(WebSocketClass::ReadyState CLOSED READ getClosed CONSTANT) public: - WebSocketClass(QScriptEngine* engine, QString url); - WebSocketClass(QScriptEngine* engine, QWebSocket* qWebSocket); + WebSocketClass(ScriptEngine* engine, QString url); + WebSocketClass(ScriptEngine* engine, QWebSocket* qWebSocket); ~WebSocketClass(); - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine); /**jsdoc * The state of a WebSocket connection. @@ -164,17 +169,17 @@ class WebSocketClass : public QObject { } } - void setOnClose(QScriptValue eventFunction) { _onCloseEvent = eventFunction; } - QScriptValue getOnClose() { return _onCloseEvent; } + void setOnClose(ScriptValuePointer eventFunction) { _onCloseEvent = eventFunction; } + ScriptValuePointer getOnClose() { return _onCloseEvent; } - void setOnError(QScriptValue eventFunction) { _onErrorEvent = eventFunction; } - QScriptValue getOnError() { return _onErrorEvent; } + void setOnError(ScriptValuePointer eventFunction) { _onErrorEvent = eventFunction; } + ScriptValuePointer getOnError() { return _onErrorEvent; } - void setOnMessage(QScriptValue eventFunction) { _onMessageEvent = eventFunction; } - QScriptValue getOnMessage() { return _onMessageEvent; } + void setOnMessage(ScriptValuePointer eventFunction) { _onMessageEvent = eventFunction; } + ScriptValuePointer getOnMessage() { return _onMessageEvent; } - void setOnOpen(QScriptValue eventFunction) { _onOpenEvent = eventFunction; } - QScriptValue getOnOpen() { return _onOpenEvent; } + void setOnOpen(ScriptValuePointer eventFunction) { _onOpenEvent = eventFunction; } + ScriptValuePointer getOnOpen() { return _onOpenEvent; } public slots: @@ -183,7 +188,7 @@ public slots: * @function WebSocket.send * @param {string|object} message - The message to send. If an object, it is converted to a string. */ - void send(QScriptValue message); + void send(ScriptValuePointer message); /**jsdoc * Closes the connection. @@ -221,12 +226,12 @@ public slots: private: QWebSocket* _webSocket; - QScriptEngine* _engine; + ScriptEngine* _engine; - QScriptValue _onCloseEvent; - QScriptValue _onErrorEvent; - QScriptValue _onMessageEvent; - QScriptValue _onOpenEvent; + ScriptValuePointer _onCloseEvent; + ScriptValuePointer _onErrorEvent; + ScriptValuePointer _onMessageEvent; + ScriptValuePointer _onOpenEvent; QString _binaryType; @@ -244,13 +249,13 @@ private slots: Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode); Q_DECLARE_METATYPE(WebSocketClass::ReadyState); -QScriptValue qWSCloseCodeToScriptValue(QScriptEngine* engine, const QWebSocketProtocol::CloseCode& closeCode); -void qWSCloseCodeFromScriptValue(const QScriptValue& object, QWebSocketProtocol::CloseCode& closeCode); +ScriptValuePointer qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProtocol::CloseCode& closeCode); +void qWSCloseCodeFromScriptValue(const ScriptValuePointer& object, QWebSocketProtocol::CloseCode& closeCode); -QScriptValue webSocketToScriptValue(QScriptEngine* engine, WebSocketClass* const &in); -void webSocketFromScriptValue(const QScriptValue &object, WebSocketClass* &out); +ScriptValuePointer webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in); +void webSocketFromScriptValue(const ScriptValuePointer &object, WebSocketClass* &out); -QScriptValue wscReadyStateToScriptValue(QScriptEngine* engine, const WebSocketClass::ReadyState& readyState); -void wscReadyStateFromScriptValue(const QScriptValue& object, WebSocketClass::ReadyState& readyState); +ScriptValuePointer wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState); +void wscReadyStateFromScriptValue(const ScriptValuePointer& object, WebSocketClass::ReadyState& readyState); #endif // hifi_WebSocketClass_h diff --git a/libraries/script-engine/src/WebSocketServerClass.cpp b/libraries/script-engine/src/WebSocketServerClass.cpp index 860170a3f98..17677a1fc69 100644 --- a/libraries/script-engine/src/WebSocketServerClass.cpp +++ b/libraries/script-engine/src/WebSocketServerClass.cpp @@ -13,9 +13,11 @@ #include "WebSocketServerClass.h" +#include "ScriptContext.h" #include "ScriptEngine.h" +#include "ScriptValue.h" -WebSocketServerClass::WebSocketServerClass(QScriptEngine* engine, const QString& serverName, const quint16 port) : +WebSocketServerClass::WebSocketServerClass(ScriptEngine* engine, const QString& serverName, const quint16 port) : _webSocketServer(serverName, QWebSocketServer::SslMode::NonSecureMode), _engine(engine) { @@ -24,24 +26,24 @@ WebSocketServerClass::WebSocketServerClass(QScriptEngine* engine, const QString& } } -QScriptValue WebSocketServerClass::constructor(QScriptContext* context, QScriptEngine* engine) { +ScriptValuePointer WebSocketServerClass::constructor(ScriptContext* context, ScriptEngine* engine) { // the serverName is used in handshakes QString serverName = QStringLiteral("HighFidelity - Scripted WebSocket Listener"); // port 0 will auto-assign a free port quint16 port = 0; - QScriptValue callee = context->callee(); + ScriptValuePointer callee = context->callee(); if (context->argumentCount() > 0) { - QScriptValue options = context->argument(0); - QScriptValue portOption = options.property(QStringLiteral("port")); - if (portOption.isValid() && portOption.isNumber()) { - port = portOption.toNumber(); + ScriptValuePointer options = context->argument(0); + ScriptValuePointer portOption = options->property(QStringLiteral("port")); + if (portOption->isValid() && portOption->isNumber()) { + port = portOption->toNumber(); } - QScriptValue serverNameOption = options.property(QStringLiteral("serverName")); - if (serverNameOption.isValid() && serverNameOption.isString()) { - serverName = serverNameOption.toString(); + ScriptValuePointer serverNameOption = options->property(QStringLiteral("serverName")); + if (serverNameOption->isValid() && serverNameOption->isString()) { + serverName = serverNameOption->toString(); } } - return engine->newQObject(new WebSocketServerClass(engine, serverName, port), QScriptEngine::ScriptOwnership); + return engine->newQObject(new WebSocketServerClass(engine, serverName, port), ScriptEngine::ScriptOwnership); } WebSocketServerClass::~WebSocketServerClass() { diff --git a/libraries/script-engine/src/WebSocketServerClass.h b/libraries/script-engine/src/WebSocketServerClass.h index a78e8544a3c..dbaa0855986 100644 --- a/libraries/script-engine/src/WebSocketServerClass.h +++ b/libraries/script-engine/src/WebSocketServerClass.h @@ -13,9 +13,14 @@ #define hifi_WebSocketServerClass_h #include -#include #include #include "WebSocketClass.h" +#include + +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * Manages {@link WebSocket}s in server entity and assignment client scripts. @@ -80,14 +85,14 @@ class WebSocketServerClass : public QObject { Q_PROPERTY(bool listening READ isListening) public: - WebSocketServerClass(QScriptEngine* engine, const QString& serverName, const quint16 port); + WebSocketServerClass(ScriptEngine* engine, const QString& serverName, const quint16 port); ~WebSocketServerClass(); QString getURL() { return _webSocketServer.serverUrl().toDisplayString(); } quint16 getPort() { return _webSocketServer.serverPort(); } bool isListening() { return _webSocketServer.isListening(); } - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine); public slots: @@ -99,7 +104,7 @@ public slots: private: QWebSocketServer _webSocketServer; - QScriptEngine* _engine; + ScriptEngine* _engine; QList _clients; private slots: diff --git a/libraries/script-engine/src/WheelEvent.cpp b/libraries/script-engine/src/WheelEvent.cpp index 2bc321691f1..a0c19392d9f 100644 --- a/libraries/script-engine/src/WheelEvent.cpp +++ b/libraries/script-engine/src/WheelEvent.cpp @@ -11,8 +11,8 @@ #include "WheelEvent.h" -#include -#include +#include "ScriptEngine.h" +#include "ScriptValue.h" WheelEvent::WheelEvent() : x(0.0f), @@ -81,22 +81,22 @@ WheelEvent::WheelEvent(const QWheelEvent& event) { * print(JSON.stringify(event)); * }); */ -QScriptValue WheelEvent::toScriptValue(QScriptEngine* engine, const WheelEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", event.x); - obj.setProperty("y", event.y); - obj.setProperty("delta", event.delta); - obj.setProperty("orientation", event.orientation); - obj.setProperty("isLeftButton", event.isLeftButton); - obj.setProperty("isRightButton", event.isRightButton); - obj.setProperty("isMiddleButton", event.isMiddleButton); - obj.setProperty("isShifted", event.isShifted); - obj.setProperty("isMeta", event.isMeta); - obj.setProperty("isControl", event.isControl); - obj.setProperty("isAlt", event.isAlt); +ScriptValuePointer WheelEvent::toScriptValue(ScriptEngine* engine, const WheelEvent& event) { + ScriptValuePointer obj = engine->newObject(); + obj->setProperty("x", event.x); + obj->setProperty("y", event.y); + obj->setProperty("delta", event.delta); + obj->setProperty("orientation", event.orientation); + obj->setProperty("isLeftButton", event.isLeftButton); + obj->setProperty("isRightButton", event.isRightButton); + obj->setProperty("isMiddleButton", event.isMiddleButton); + obj->setProperty("isShifted", event.isShifted); + obj->setProperty("isMeta", event.isMeta); + obj->setProperty("isControl", event.isControl); + obj->setProperty("isAlt", event.isAlt); return obj; } -void WheelEvent::fromScriptValue(const QScriptValue& object, WheelEvent& event) { +void WheelEvent::fromScriptValue(const ScriptValuePointer& object, WheelEvent& event) { // nothing for now... } diff --git a/libraries/script-engine/src/WheelEvent.h b/libraries/script-engine/src/WheelEvent.h index 88ac8285780..d2303b99734 100644 --- a/libraries/script-engine/src/WheelEvent.h +++ b/libraries/script-engine/src/WheelEvent.h @@ -14,17 +14,19 @@ #include #include +#include -class QScriptValue; -class QScriptEngine; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class WheelEvent { public: WheelEvent(); WheelEvent(const QWheelEvent& event); - static QScriptValue toScriptValue(QScriptEngine* engine, const WheelEvent& event); - static void fromScriptValue(const QScriptValue& object, WheelEvent& event); + static ScriptValuePointer toScriptValue(ScriptEngine* engine, const WheelEvent& event); + static void fromScriptValue(const ScriptValuePointer& object, WheelEvent& event); int x; int y; diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 1a4ec52f73d..c78d287fe00 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -23,12 +23,16 @@ #include #include "ResourceRequestObserver.h" +#include "ScriptContext.h" #include "ScriptEngine.h" +#include "ScriptValue.h" Q_DECLARE_METATYPE(QByteArray*) -XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : +XMLHttpRequestClass::XMLHttpRequestClass(ScriptEngine* engine) : _engine(engine), + _onTimeout(engine->nullValue()), + _onReadyStateChange(engine->nullValue()), _timer(this) { _request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); @@ -39,15 +43,15 @@ XMLHttpRequestClass::~XMLHttpRequestClass() { if (_reply) { _reply->deleteLater(); } } -QScriptValue XMLHttpRequestClass::constructor(QScriptContext* context, QScriptEngine* engine) { - return engine->newQObject(new XMLHttpRequestClass(engine), QScriptEngine::ScriptOwnership); +ScriptValuePointer XMLHttpRequestClass::constructor(ScriptContext* context, ScriptEngine* engine) { + return engine->newQObject(new XMLHttpRequestClass(engine), ScriptEngine::ScriptOwnership); } -QScriptValue XMLHttpRequestClass::getStatus() const { +ScriptValuePointer XMLHttpRequestClass::getStatus() const { if (_reply) { - return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); + return _engine->newValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); } - return QScriptValue(0); + return ScriptValuePointer(0); } QString XMLHttpRequestClass::getStatusText() const { @@ -87,7 +91,7 @@ void XMLHttpRequestClass::requestDownloadProgress(qint64 bytesReceived, qint64 b } } -QScriptValue XMLHttpRequestClass::getAllResponseHeaders() const { +ScriptValuePointer XMLHttpRequestClass::getAllResponseHeaders() const { if (_reply) { QList headerList = _reply->rawHeaderPairs(); QByteArray headers; @@ -97,16 +101,16 @@ QScriptValue XMLHttpRequestClass::getAllResponseHeaders() const { headers.append(headerList[i].second); headers.append("\n"); } - return QString(headers.data()); + return _engine->newValue(QString(headers.data())); } - return QScriptValue(""); + return _engine->newValue(""); } -QScriptValue XMLHttpRequestClass::getResponseHeader(const QString& name) const { +ScriptValuePointer XMLHttpRequestClass::getResponseHeader(const QString& name) const { if (_reply && _reply->hasRawHeader(name.toLatin1())) { - return QScriptValue(QString(_reply->rawHeader(name.toLatin1()))); + return _engine->newValue(QString(_reply->rawHeader(name.toLatin1()))); } - return QScriptValue::NullValue; + return _engine->nullValue(); } /**jsdoc @@ -116,8 +120,8 @@ QScriptValue XMLHttpRequestClass::getResponseHeader(const QString& name) const { void XMLHttpRequestClass::setReadyState(ReadyState readyState) { if (readyState != _readyState) { _readyState = readyState; - if (_onReadyStateChange.isFunction()) { - _onReadyStateChange.call(QScriptValue::NullValue); + if (_onReadyStateChange->isFunction()) { + _onReadyStateChange->call(_onReadyStateChange->engine()->nullValue()); } } } @@ -153,17 +157,17 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a } void XMLHttpRequestClass::send() { - send(QScriptValue::NullValue); + send(_engine->nullValue()); } -void XMLHttpRequestClass::send(const QScriptValue& data) { +void XMLHttpRequestClass::send(const ScriptValuePointer& data) { if (_readyState == OPENED && !_reply) { if (!data.isNull()) { - if (data.isObject()) { - _sendData = qscriptvalue_cast(data); + if (data->isObject()) { + _sendData = scriptvalue_cast(data); } else { - _sendData = data.toString().toUtf8(); + _sendData = data->toString().toUtf8(); } } @@ -193,8 +197,8 @@ void XMLHttpRequestClass::doSend() { * @callback XMLHttpRequest~onTimeoutCallback */ void XMLHttpRequestClass::requestTimeout() { - if (_onTimeout.isFunction()) { - _onTimeout.call(QScriptValue::NullValue); + if (_onTimeout->isFunction()) { + _onTimeout->call(_engine->nullValue()); } abortRequest(); _errorCode = QNetworkReply::TimeoutError; @@ -215,15 +219,14 @@ void XMLHttpRequestClass::requestFinished() { if (_responseType == "json") { _responseData = _engine->evaluate("(" + QString(_rawResponseData.data()) + ")"); - if (_responseData.isError()) { + if (_responseData->isError()) { _engine->clearExceptions(); - _responseData = QScriptValue::NullValue; + _responseData = _engine->nullValue(); } } else if (_responseType == "arraybuffer") { - QScriptValue data = _engine->newVariant(QVariant::fromValue(_rawResponseData)); - _responseData = _engine->newObject(reinterpret_cast(_engine)->getArrayBufferClass(), data); + _responseData = _engine->newArrayBuffer(_rawResponseData); } else { - _responseData = QScriptValue(QString(_rawResponseData.data())); + _responseData = _engine->newValue(QString(_rawResponseData.data())); } } diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h index 01127e786db..8d3221c1955 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.h +++ b/libraries/script-engine/src/XMLHttpRequestClass.h @@ -16,10 +16,14 @@ #include #include #include -#include -#include -#include #include +#include + +#include "ScriptEngine.h" + +class ScriptContext; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /* XMlHttpRequest object @@ -51,7 +55,7 @@ XMlHttpRequest.open(QString,QString,bool,QString) function XMlHttpRequest.open(QString,QString,bool) function XMlHttpRequest.open(QString,QString) function XMlHttpRequest.send() function -XMlHttpRequest.send(QScriptValue) function +XMlHttpRequest.send(ScriptValuePointer) function XMlHttpRequest.getAllResponseHeaders() function XMlHttpRequest.getResponseHeader(QString) function */ @@ -151,13 +155,13 @@ XMlHttpRequest.getResponseHeader(QString) function */ class XMLHttpRequestClass : public QObject { Q_OBJECT - Q_PROPERTY(QScriptValue response READ getResponse) - Q_PROPERTY(QScriptValue responseText READ getResponseText) + Q_PROPERTY(ScriptValuePointer response READ getResponse) + Q_PROPERTY(ScriptValuePointer responseText READ getResponseText) Q_PROPERTY(QString responseType READ getResponseType WRITE setResponseType) - Q_PROPERTY(QScriptValue status READ getStatus) + Q_PROPERTY(ScriptValuePointer status READ getStatus) Q_PROPERTY(QString statusText READ getStatusText) - Q_PROPERTY(QScriptValue readyState READ getReadyState) - Q_PROPERTY(QScriptValue errorCode READ getError) + Q_PROPERTY(ScriptValuePointer readyState READ getReadyState) + Q_PROPERTY(ScriptValuePointer errorCode READ getError) Q_PROPERTY(int timeout READ getTimeout WRITE setTimeout) Q_PROPERTY(int UNSENT READ getUnsent) @@ -167,10 +171,10 @@ class XMLHttpRequestClass : public QObject { Q_PROPERTY(int DONE READ getDone) // Callbacks - Q_PROPERTY(QScriptValue ontimeout READ getOnTimeout WRITE setOnTimeout) - Q_PROPERTY(QScriptValue onreadystatechange READ getOnReadyStateChange WRITE setOnReadyStateChange) + Q_PROPERTY(ScriptValuePointer ontimeout READ getOnTimeout WRITE setOnTimeout) + Q_PROPERTY(ScriptValuePointer onreadystatechange READ getOnReadyStateChange WRITE setOnReadyStateChange) public: - XMLHttpRequestClass(QScriptEngine* engine); + XMLHttpRequestClass(ScriptEngine* engine); ~XMLHttpRequestClass(); static const int MAXIMUM_REDIRECTS = 5; @@ -208,23 +212,23 @@ class XMLHttpRequestClass : public QObject { int getLoading() const { return LOADING; }; int getDone() const { return DONE; }; - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine); int getTimeout() const { return _timeout; } void setTimeout(int timeout) { _timeout = timeout; } - QScriptValue getResponse() const { return _responseData; } - QScriptValue getResponseText() const { return QScriptValue(QString(_rawResponseData.data())); } + ScriptValuePointer getResponse() const { return _responseData; } + ScriptValuePointer getResponseText() const { return _engine->newValue(QString(_rawResponseData.data())); } QString getResponseType() const { return _responseType; } void setResponseType(const QString& responseType) { _responseType = responseType; } - QScriptValue getReadyState() const { return QScriptValue(_readyState); } - QScriptValue getError() const { return QScriptValue(_errorCode); } - QScriptValue getStatus() const; + ScriptValuePointer getReadyState() const { return _engine->newValue(_readyState); } + ScriptValuePointer getError() const { return _engine->newValue(_errorCode); } + ScriptValuePointer getStatus() const; QString getStatusText() const; - QScriptValue getOnTimeout() const { return _onTimeout; } - void setOnTimeout(QScriptValue function) { _onTimeout = function; } - QScriptValue getOnReadyStateChange() const { return _onReadyStateChange; } - void setOnReadyStateChange(QScriptValue function) { _onReadyStateChange = function; } + ScriptValuePointer getOnTimeout() const { return _onTimeout; } + void setOnTimeout(ScriptValuePointer function) { _onTimeout = function; } + ScriptValuePointer getOnReadyStateChange() const { return _onReadyStateChange; } + void setOnReadyStateChange(ScriptValuePointer function) { _onReadyStateChange = function; } public slots: @@ -263,14 +267,14 @@ public slots: * @param {*} [data] - The data to send. */ void send(); - void send(const QScriptValue& data); + void send(const ScriptValuePointer& data); /**jsdoc * Gets the response headers. * @function XMLHttpRequest.getAllResponseHeaders * @returns {string} The response headers, separated by "\n" characters. */ - QScriptValue getAllResponseHeaders() const; + ScriptValuePointer getAllResponseHeaders() const; /**jsdoc * Gets a response header. @@ -278,7 +282,7 @@ public slots: * @param {string} name - * @returns {string} The response header. */ - QScriptValue getResponseHeader(const QString& name) const; + ScriptValuePointer getResponseHeader(const QString& name) const; signals: @@ -296,7 +300,7 @@ public slots: void disconnectFromReply(QNetworkReply* reply); void abortRequest(); - QScriptEngine* _engine { nullptr }; + ScriptEngine* _engine { nullptr }; bool _async { true }; QUrl _url; QString _method; @@ -305,9 +309,9 @@ public slots: QNetworkReply* _reply { nullptr }; QByteArray _sendData; QByteArray _rawResponseData; - QScriptValue _responseData; - QScriptValue _onTimeout { QScriptValue::NullValue }; - QScriptValue _onReadyStateChange { QScriptValue::NullValue }; + ScriptValuePointer _responseData; + ScriptValuePointer _onTimeout; + ScriptValuePointer _onReadyStateChange; ReadyState _readyState { XMLHttpRequestClass::UNSENT }; /**jsdoc diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 57904be5867..e9291974f56 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -3,7 +3,7 @@ set(TARGET_NAME shared) include_directories("${QT_DIR}/include/QtCore/${QT_VERSION}/QtCore" "${QT_DIR}/include/QtCore/${QT_VERSION}") # TODO: there isn't really a good reason to have Script linked here - let's get what is requiring it out (RegisteredMetaTypes.cpp) -setup_hifi_library(Gui Network Script) +setup_hifi_library(Gui Network) if (WIN32) target_link_libraries(${TARGET_NAME} Wbemuuid.lib) diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index d47cc0769a5..367a106a69b 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -22,8 +22,6 @@ #include #include #include -#include -#include #include int uint32MetaTypeId = qRegisterMetaType("uint32"); @@ -46,81 +44,6 @@ int voidLambdaType = qRegisterMetaType>(); int variantLambdaType = qRegisterMetaType>(); int stencilModeMetaTypeId = qRegisterMetaType(); -void registerMetaTypes(QScriptEngine* engine) { - qScriptRegisterMetaType(engine, vec2ToScriptValue, vec2FromScriptValue); - qScriptRegisterMetaType(engine, vec3ToScriptValue, vec3FromScriptValue); - qScriptRegisterMetaType(engine, u8vec3ToScriptValue, u8vec3FromScriptValue); - qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); - qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); - qScriptRegisterMetaType(engine, mat4toScriptValue, mat4FromScriptValue); - - qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue); - qScriptRegisterMetaType(engine, qVectorQuatToScriptValue, qVectorQuatFromScriptValue); - qScriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue); - qScriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue); - qScriptRegisterMetaType(engine, qVectorIntToScriptValue, qVectorIntFromScriptValue); - qScriptRegisterMetaType(engine, qVectorQUuidToScriptValue, qVectorQUuidFromScriptValue); - - qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue); - qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue); - qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue); - qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); - - qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); - qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); - qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); - qScriptRegisterMetaType(engine, aaCubeToScriptValue, aaCubeFromScriptValue); - - qScriptRegisterMetaType(engine, stencilMaskModeToScriptValue, stencilMaskModeFromScriptValue); - - qScriptRegisterSequenceMetaType>(engine); -} - -QScriptValue vec2ToScriptValue(QScriptEngine* engine, const glm::vec2& vec2) { - auto prototype = engine->globalObject().property("__hifi_vec2__"); - if (!prototype.property("defined").toBool()) { - prototype = engine->evaluate( - "__hifi_vec2__ = Object.defineProperties({}, { " - "defined: { value: true }," - "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," - "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," - "u: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," - "v: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }" - "})" - ); - } - QScriptValue value = engine->newObject(); - value.setProperty("x", vec2.x); - value.setProperty("y", vec2.y); - value.setPrototype(prototype); - return value; -} - -void vec2FromScriptValue(const QScriptValue& object, glm::vec2& vec2) { - if (object.isNumber()) { - vec2 = glm::vec2(object.toVariant().toFloat()); - } else if (object.isArray()) { - QVariantList list = object.toVariant().toList(); - if (list.length() == 2) { - vec2.x = list[0].toFloat(); - vec2.y = list[1].toFloat(); - } - } else { - QScriptValue x = object.property("x"); - if (!x.isValid()) { - x = object.property("u"); - } - - QScriptValue y = object.property("y"); - if (!y.isValid()) { - y = object.property("v"); - } - - vec2.x = x.toVariant().toFloat(); - vec2.y = y.toVariant().toFloat(); - } -} - QVariant vec2ToVariant(const glm::vec2 &vec2) { if (vec2.x != vec2.x || vec2.y != vec2.y) { // if vec2 contains a NaN don't try to convert it @@ -170,206 +93,6 @@ glm::vec2 vec2FromVariant(const QVariant &object) { return vec2FromVariant(object, valid); } -QScriptValue vec3ToScriptValue(QScriptEngine* engine, const glm::vec3& vec3) { - auto prototype = engine->globalObject().property("__hifi_vec3__"); - if (!prototype.property("defined").toBool()) { - prototype = engine->evaluate( - "__hifi_vec3__ = Object.defineProperties({}, { " - "defined: { value: true }," - "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," - "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," - "2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }," - "r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," - "g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," - "b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }," - "red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," - "green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," - "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }" - "})" - ); - } - QScriptValue value = engine->newObject(); - value.setProperty("x", vec3.x); - value.setProperty("y", vec3.y); - value.setProperty("z", vec3.z); - value.setPrototype(prototype); - return value; -} - -QScriptValue vec3ColorToScriptValue(QScriptEngine* engine, const glm::vec3& vec3) { - auto prototype = engine->globalObject().property("__hifi_vec3_color__"); - if (!prototype.property("defined").toBool()) { - prototype = engine->evaluate( - "__hifi_vec3_color__ = Object.defineProperties({}, { " - "defined: { value: true }," - "0: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," - "1: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," - "2: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }," - "r: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," - "g: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," - "b: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }," - "x: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," - "y: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," - "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }" - "})" - ); - } - QScriptValue value = engine->newObject(); - value.setProperty("red", vec3.x); - value.setProperty("green", vec3.y); - value.setProperty("blue", vec3.z); - value.setPrototype(prototype); - return value; -} - -void vec3FromScriptValue(const QScriptValue& object, glm::vec3& vec3) { - if (object.isNumber()) { - vec3 = glm::vec3(object.toVariant().toFloat()); - } else if (object.isString()) { - QColor qColor(object.toString()); - if (qColor.isValid()) { - vec3.x = qColor.red(); - vec3.y = qColor.green(); - vec3.z = qColor.blue(); - } - } else if (object.isArray()) { - QVariantList list = object.toVariant().toList(); - if (list.length() == 3) { - vec3.x = list[0].toFloat(); - vec3.y = list[1].toFloat(); - vec3.z = list[2].toFloat(); - } - } else { - QScriptValue x = object.property("x"); - if (!x.isValid()) { - x = object.property("r"); - } - if (!x.isValid()) { - x = object.property("red"); - } - - QScriptValue y = object.property("y"); - if (!y.isValid()) { - y = object.property("g"); - } - if (!y.isValid()) { - y = object.property("green"); - } - - QScriptValue z = object.property("z"); - if (!z.isValid()) { - z = object.property("b"); - } - if (!z.isValid()) { - z = object.property("blue"); - } - - vec3.x = x.toVariant().toFloat(); - vec3.y = y.toVariant().toFloat(); - vec3.z = z.toVariant().toFloat(); - } -} - -QScriptValue u8vec3ToScriptValue(QScriptEngine* engine, const glm::u8vec3& vec3) { - auto prototype = engine->globalObject().property("__hifi_u8vec3__"); - if (!prototype.property("defined").toBool()) { - prototype = engine->evaluate( - "__hifi_u8vec3__ = Object.defineProperties({}, { " - "defined: { value: true }," - "0: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," - "1: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," - "2: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }," - "r: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," - "g: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," - "b: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }," - "red: { set: function(nv) { return this.x = nv; }, get: function() { return this.x; } }," - "green: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }," - "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }" - "})" - ); - } - QScriptValue value = engine->newObject(); - value.setProperty("x", vec3.x); - value.setProperty("y", vec3.y); - value.setProperty("z", vec3.z); - value.setPrototype(prototype); - return value; -} - -QScriptValue u8vec3ColorToScriptValue(QScriptEngine* engine, const glm::u8vec3& vec3) { - auto prototype = engine->globalObject().property("__hifi_u8vec3_color__"); - if (!prototype.property("defined").toBool()) { - prototype = engine->evaluate( - "__hifi_u8vec3_color__ = Object.defineProperties({}, { " - "defined: { value: true }," - "0: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," - "1: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," - "2: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }," - "r: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," - "g: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," - "b: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }," - "x: { set: function(nv) { return this.red = nv; }, get: function() { return this.red; } }," - "y: { set: function(nv) { return this.green = nv; }, get: function() { return this.green; } }," - "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }" - "})" - ); - } - QScriptValue value = engine->newObject(); - value.setProperty("red", vec3.x); - value.setProperty("green", vec3.y); - value.setProperty("blue", vec3.z); - value.setPrototype(prototype); - return value; -} - -void u8vec3FromScriptValue(const QScriptValue& object, glm::u8vec3& vec3) { - if (object.isNumber()) { - vec3 = glm::vec3(object.toVariant().toUInt()); - } else if (object.isString()) { - QColor qColor(object.toString()); - if (qColor.isValid()) { - vec3.x = (uint8_t)qColor.red(); - vec3.y = (uint8_t)qColor.green(); - vec3.z = (uint8_t)qColor.blue(); - } - } else if (object.isArray()) { - QVariantList list = object.toVariant().toList(); - if (list.length() == 3) { - vec3.x = list[0].toUInt(); - vec3.y = list[1].toUInt(); - vec3.z = list[2].toUInt(); - } - } else { - QScriptValue x = object.property("x"); - if (!x.isValid()) { - x = object.property("r"); - } - if (!x.isValid()) { - x = object.property("red"); - } - - QScriptValue y = object.property("y"); - if (!y.isValid()) { - y = object.property("g"); - } - if (!y.isValid()) { - y = object.property("green"); - } - - QScriptValue z = object.property("z"); - if (!z.isValid()) { - z = object.property("b"); - } - if (!z.isValid()) { - z = object.property("blue"); - } - - vec3.x = x.toVariant().toUInt(); - vec3.y = y.toVariant().toUInt(); - vec3.z = z.toVariant().toUInt(); - } -} - QVariant vec3toVariant(const glm::vec3& vec3) { if (vec3.x != vec3.x || vec3.y != vec3.y || vec3.z != vec3.z) { // if vec3 contains a NaN don't try to convert it @@ -540,22 +263,6 @@ glm::u8vec3 u8vec3FromVariant(const QVariant& object) { return u8vec3FromVariant(object, valid); } -QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", vec4.x); - obj.setProperty("y", vec4.y); - obj.setProperty("z", vec4.z); - obj.setProperty("w", vec4.w); - return obj; -} - -void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4) { - vec4.x = object.property("x").toVariant().toFloat(); - vec4.y = object.property("y").toVariant().toFloat(); - vec4.z = object.property("z").toVariant().toFloat(); - vec4.w = object.property("w").toVariant().toFloat(); -} - QVariant vec4toVariant(const glm::vec4& vec4) { if (isNaN(vec4.x) || isNaN(vec4.y) || isNaN(vec4.z) || isNaN(vec4.w)) { // if vec4 contains a NaN don't try to convert it @@ -606,46 +313,6 @@ glm::vec4 vec4FromVariant(const QVariant& object) { return vec4FromVariant(object, valid); } -QScriptValue mat4toScriptValue(QScriptEngine* engine, const glm::mat4& mat4) { - QScriptValue obj = engine->newObject(); - obj.setProperty("r0c0", mat4[0][0]); - obj.setProperty("r1c0", mat4[0][1]); - obj.setProperty("r2c0", mat4[0][2]); - obj.setProperty("r3c0", mat4[0][3]); - obj.setProperty("r0c1", mat4[1][0]); - obj.setProperty("r1c1", mat4[1][1]); - obj.setProperty("r2c1", mat4[1][2]); - obj.setProperty("r3c1", mat4[1][3]); - obj.setProperty("r0c2", mat4[2][0]); - obj.setProperty("r1c2", mat4[2][1]); - obj.setProperty("r2c2", mat4[2][2]); - obj.setProperty("r3c2", mat4[2][3]); - obj.setProperty("r0c3", mat4[3][0]); - obj.setProperty("r1c3", mat4[3][1]); - obj.setProperty("r2c3", mat4[3][2]); - obj.setProperty("r3c3", mat4[3][3]); - return obj; -} - -void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4) { - mat4[0][0] = object.property("r0c0").toVariant().toFloat(); - mat4[0][1] = object.property("r1c0").toVariant().toFloat(); - mat4[0][2] = object.property("r2c0").toVariant().toFloat(); - mat4[0][3] = object.property("r3c0").toVariant().toFloat(); - mat4[1][0] = object.property("r0c1").toVariant().toFloat(); - mat4[1][1] = object.property("r1c1").toVariant().toFloat(); - mat4[1][2] = object.property("r2c1").toVariant().toFloat(); - mat4[1][3] = object.property("r3c1").toVariant().toFloat(); - mat4[2][0] = object.property("r0c2").toVariant().toFloat(); - mat4[2][1] = object.property("r1c2").toVariant().toFloat(); - mat4[2][2] = object.property("r2c2").toVariant().toFloat(); - mat4[2][3] = object.property("r3c2").toVariant().toFloat(); - mat4[3][0] = object.property("r0c3").toVariant().toFloat(); - mat4[3][1] = object.property("r1c3").toVariant().toFloat(); - mat4[3][2] = object.property("r2c3").toVariant().toFloat(); - mat4[3][3] = object.property("r3c3").toVariant().toFloat(); -} - QVariant mat4ToVariant(const glm::mat4& mat4) { if (mat4 != mat4) { // NaN @@ -721,72 +388,6 @@ glm::mat4 mat4FromVariant(const QVariant& object) { return mat4FromVariant(object, valid); } -QScriptValue qVectorVec3ColorToScriptValue(QScriptEngine* engine, const QVector& vector) { - QScriptValue array = engine->newArray(); - for (int i = 0; i < vector.size(); i++) { - array.setProperty(i, vec3ColorToScriptValue(engine, vector.at(i))); - } - return array; -} - -QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector) { - QScriptValue array = engine->newArray(); - for (int i = 0; i < vector.size(); i++) { - array.setProperty(i, vec3ToScriptValue(engine, vector.at(i))); - } - return array; -} - -QVector qVectorVec3FromScriptValue(const QScriptValue& array) { - QVector newVector; - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - glm::vec3 newVec3 = glm::vec3(); - vec3FromScriptValue(array.property(i), newVec3); - newVector << newVec3; - } - return newVector; -} - -void qVectorVec3FromScriptValue(const QScriptValue& array, QVector& vector) { - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - glm::vec3 newVec3 = glm::vec3(); - vec3FromScriptValue(array.property(i), newVec3); - vector << newVec3; - } -} - -QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat) { - QScriptValue obj = engine->newObject(); - if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) { - // if quat contains a NaN don't try to convert it - return obj; - } - obj.setProperty("x", quat.x); - obj.setProperty("y", quat.y); - obj.setProperty("z", quat.z); - obj.setProperty("w", quat.w); - return obj; -} - -void quatFromScriptValue(const QScriptValue& object, glm::quat &quat) { - quat.x = object.property("x").toVariant().toFloat(); - quat.y = object.property("y").toVariant().toFloat(); - quat.z = object.property("z").toVariant().toFloat(); - quat.w = object.property("w").toVariant().toFloat(); - - // enforce normalized quaternion - float length = glm::length(quat); - if (length > FLT_EPSILON) { - quat /= length; - } else { - quat = glm::quat(); - } -} - glm::quat quatFromVariant(const QVariant &object, bool& isValid) { glm::quat q; if (object.canConvert()) { @@ -844,159 +445,6 @@ QVariant quatToVariant(const glm::quat& quat) { return result; } -QScriptValue qVectorQuatToScriptValue(QScriptEngine* engine, const QVector& vector) { - QScriptValue array = engine->newArray(); - for (int i = 0; i < vector.size(); i++) { - array.setProperty(i, quatToScriptValue(engine, vector.at(i))); - } - return array; -} - -QScriptValue qVectorBoolToScriptValue(QScriptEngine* engine, const QVector& vector) { - QScriptValue array = engine->newArray(); - for (int i = 0; i < vector.size(); i++) { - array.setProperty(i, vector.at(i)); - } - return array; -} - -QVector qVectorFloatFromScriptValue(const QScriptValue& array) { - if(!array.isArray()) { - return QVector(); - } - QVector newVector; - int length = array.property("length").toInteger(); - newVector.reserve(length); - for (int i = 0; i < length; i++) { - if(array.property(i).isNumber()) { - newVector << array.property(i).toNumber(); - } - } - - return newVector; -} - -QScriptValue qVectorQUuidToScriptValue(QScriptEngine* engine, const QVector& vector) { - QScriptValue array = engine->newArray(); - for (int i = 0; i < vector.size(); i++) { - array.setProperty(i, quuidToScriptValue(engine, vector.at(i))); - } - return array; -} - -void qVectorQUuidFromScriptValue(const QScriptValue& array, QVector& vector) { - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - vector << array.property(i).toVariant().toUuid(); - } -} - -QVector qVectorQUuidFromScriptValue(const QScriptValue& array) { - if (!array.isArray()) { - return QVector(); - } - QVector newVector; - int length = array.property("length").toInteger(); - newVector.reserve(length); - for (int i = 0; i < length; i++) { - QString uuidAsString = array.property(i).toString(); - QUuid fromString(uuidAsString); - newVector << fromString; - } - return newVector; -} - -QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector& vector) { - QScriptValue array = engine->newArray(); - for (int i = 0; i < vector.size(); i++) { - float num = vector.at(i); - array.setProperty(i, QScriptValue(num)); - } - return array; -} - -QScriptValue qVectorIntToScriptValue(QScriptEngine* engine, const QVector& vector) { - QScriptValue array = engine->newArray(); - for (int i = 0; i < vector.size(); i++) { - int num = vector.at(i); - array.setProperty(i, QScriptValue(num)); - } - return array; -} - -void qVectorFloatFromScriptValue(const QScriptValue& array, QVector& vector) { - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - vector << array.property(i).toVariant().toFloat(); - } -} - -void qVectorIntFromScriptValue(const QScriptValue& array, QVector& vector) { - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - vector << array.property(i).toVariant().toInt(); - } -} - -QVector qVectorQuatFromScriptValue(const QScriptValue& array){ - QVector newVector; - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - glm::quat newQuat = glm::quat(); - quatFromScriptValue(array.property(i), newQuat); - newVector << newQuat; - } - return newVector; -} - -void qVectorQuatFromScriptValue(const QScriptValue& array, QVector& vector ) { - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - glm::quat newQuat = glm::quat(); - quatFromScriptValue(array.property(i), newQuat); - vector << newQuat; - } -} - -QVector qVectorBoolFromScriptValue(const QScriptValue& array){ - QVector newVector; - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - newVector << array.property(i).toBool(); - } - return newVector; -} - -void qVectorBoolFromScriptValue(const QScriptValue& array, QVector& vector ) { - int length = array.property("length").toInteger(); - - for (int i = 0; i < length; i++) { - vector << array.property(i).toBool(); - } -} - -QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", rect.x()); - obj.setProperty("y", rect.y()); - obj.setProperty("width", rect.width()); - obj.setProperty("height", rect.height()); - return obj; -} - -void qRectFromScriptValue(const QScriptValue &object, QRect& rect) { - rect.setX(object.property("x").toVariant().toInt()); - rect.setY(object.property("y").toVariant().toInt()); - rect.setWidth(object.property("width").toVariant().toInt()); - rect.setHeight(object.property("height").toVariant().toInt()); -} - QVariant qRectToVariant(const QRect& rect) { QVariantMap obj; obj["x"] = rect.x(); @@ -1028,22 +476,6 @@ QRect qRectFromVariant(const QVariant& object) { return qRectFromVariant(object, valid); } -QScriptValue qRectFToScriptValue(QScriptEngine* engine, const QRectF& rect) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", rect.x()); - obj.setProperty("y", rect.y()); - obj.setProperty("width", rect.width()); - obj.setProperty("height", rect.height()); - return obj; -} - -void qRectFFromScriptValue(const QScriptValue &object, QRectF& rect) { - rect.setX(object.property("x").toVariant().toFloat()); - rect.setY(object.property("y").toVariant().toFloat()); - rect.setWidth(object.property("width").toVariant().toFloat()); - rect.setHeight(object.property("height").toVariant().toFloat()); -} - QVariant qRectFToVariant(const QRectF& rect) { QVariantMap obj; obj["x"] = rect.x(); @@ -1075,100 +507,6 @@ QRectF qRectFFromVariant(const QVariant& object) { return qRectFFromVariant(object, valid); } -QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color) { - QScriptValue object = engine->newObject(); - object.setProperty("red", color.red()); - object.setProperty("green", color.green()); - object.setProperty("blue", color.blue()); - object.setProperty("alpha", color.alpha()); - return object; -} - -/**jsdoc - * An axis-aligned cube, defined as the bottom right near (minimum axes values) corner of the cube plus the dimension of its - * sides. - * @typedef {object} AACube - * @property {number} x - X coordinate of the brn corner of the cube. - * @property {number} y - Y coordinate of the brn corner of the cube. - * @property {number} z - Z coordinate of the brn corner of the cube. - * @property {number} scale - The dimensions of each side of the cube. - */ -QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube) { - QScriptValue obj = engine->newObject(); - const glm::vec3& corner = aaCube.getCorner(); - obj.setProperty("x", corner.x); - obj.setProperty("y", corner.y); - obj.setProperty("z", corner.z); - obj.setProperty("scale", aaCube.getScale()); - return obj; -} - -void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube) { - glm::vec3 corner; - corner.x = object.property("x").toVariant().toFloat(); - corner.y = object.property("y").toVariant().toFloat(); - corner.z = object.property("z").toVariant().toFloat(); - float scale = object.property("scale").toVariant().toFloat(); - - aaCube.setBox(corner, scale); -} - -void qColorFromScriptValue(const QScriptValue& object, QColor& color) { - if (object.isNumber()) { - color.setRgb(object.toUInt32()); - - } else if (object.isString()) { - color.setNamedColor(object.toString()); - - } else { - QScriptValue alphaValue = object.property("alpha"); - color.setRgb(object.property("red").toInt32(), object.property("green").toInt32(), object.property("blue").toInt32(), - alphaValue.isNumber() ? alphaValue.toInt32() : 255); - } -} - -QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url) { - return url.toString(); -} - -void qURLFromScriptValue(const QScriptValue& object, QUrl& url) { - url = object.toString(); -} - -QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay) { - QScriptValue obj = engine->newObject(); - QScriptValue origin = vec3ToScriptValue(engine, pickRay.origin); - obj.setProperty("origin", origin); - QScriptValue direction = vec3ToScriptValue(engine, pickRay.direction); - obj.setProperty("direction", direction); - return obj; -} - -void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { - QScriptValue originValue = object.property("origin"); - if (originValue.isValid()) { - auto x = originValue.property("x"); - auto y = originValue.property("y"); - auto z = originValue.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - pickRay.origin.x = x.toVariant().toFloat(); - pickRay.origin.y = y.toVariant().toFloat(); - pickRay.origin.z = z.toVariant().toFloat(); - } - } - QScriptValue directionValue = object.property("direction"); - if (directionValue.isValid()) { - auto x = directionValue.property("x"); - auto y = directionValue.property("y"); - auto z = directionValue.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - pickRay.direction.x = x.toVariant().toFloat(); - pickRay.direction.y = y.toVariant().toFloat(); - pickRay.direction.z = z.toVariant().toFloat(); - } - } -} - /**jsdoc * Details of a collision between avatars and entities. * @typedef {object} Collision @@ -1179,63 +517,12 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { * @property {Vec3} contactPoint - The point of contact. * @property {Vec3} velocityChange - The change in relative velocity of the two items, in m/s. */ -QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision) { - QScriptValue obj = engine->newObject(); - obj.setProperty("type", collision.type); - obj.setProperty("idA", quuidToScriptValue(engine, collision.idA)); - obj.setProperty("idB", quuidToScriptValue(engine, collision.idB)); - obj.setProperty("penetration", vec3ToScriptValue(engine, collision.penetration)); - obj.setProperty("contactPoint", vec3ToScriptValue(engine, collision.contactPoint)); - obj.setProperty("velocityChange", vec3ToScriptValue(engine, collision.velocityChange)); - return obj; -} - -void collisionFromScriptValue(const QScriptValue &object, Collision& collision) { - // TODO: implement this when we know what it means to accept collision events from JS -} - void Collision::invert() { std::swap(idA, idB); contactPoint += penetration; penetration *= -1.0f; } -QScriptValue quuidToScriptValue(QScriptEngine* engine, const QUuid& uuid) { - if (uuid.isNull()) { - return QScriptValue::NullValue; - } - QScriptValue obj(uuid.toString()); - return obj; -} - -void quuidFromScriptValue(const QScriptValue& object, QUuid& uuid) { - if (object.isNull()) { - uuid = QUuid(); - return; - } - QString uuidAsString = object.toVariant().toString(); - QUuid fromString(uuidAsString); - uuid = fromString; -} - -/**jsdoc - * A 2D size value. - * @typedef {object} Size - * @property {number} height - The height value. - * @property {number} width - The width value. - */ -QScriptValue qSizeFToScriptValue(QScriptEngine* engine, const QSizeF& qSizeF) { - QScriptValue obj = engine->newObject(); - obj.setProperty("width", qSizeF.width()); - obj.setProperty("height", qSizeF.height()); - return obj; -} - -void qSizeFFromScriptValue(const QScriptValue& object, QSizeF& qSizeF) { - qSizeF.setWidth(object.property("width").toVariant().toFloat()); - qSizeF.setHeight(object.property("height").toVariant().toFloat()); -} - AnimationDetails::AnimationDetails() : role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false), startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), currentFrame(0.0f) { @@ -1248,116 +535,6 @@ AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float prio running(running), currentFrame(currentFrame), allowTranslation(allowTranslation) { } -/**jsdoc - * The details of an animation that is playing. - * @typedef {object} Avatar.AnimationDetails - * @property {string} role - Not used. - * @property {string} url - The URL to the animation file. Animation files need to be in glTF or FBX format but only need to - * contain the avatar skeleton and animation data. glTF models may be in JSON or binary format (".gltf" or ".glb" URLs - * respectively). - *

Warning: glTF animations currently do not always animate correctly.

- * @property {number} fps - The frames per second(FPS) rate for the animation playback. 30 FPS is normal speed. - * @property {number} priority - Not used. - * @property {boolean} loop - true if the animation should loop, false if it shouldn't. - * @property {boolean} hold - Not used. - * @property {number} firstFrame - The frame the animation should start at. - * @property {number} lastFrame - The frame the animation should stop at. - * @property {boolean} running - Not used. - * @property {number} currentFrame - The current frame being played. - * @property {boolean} startAutomatically - Not used. - * @property {boolean} allowTranslation - Not used. - */ -QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& details) { - QScriptValue obj = engine->newObject(); - obj.setProperty("role", details.role); - obj.setProperty("url", details.url.toString()); - obj.setProperty("fps", details.fps); - obj.setProperty("priority", details.priority); - obj.setProperty("loop", details.loop); - obj.setProperty("hold", details.hold); - obj.setProperty("startAutomatically", details.startAutomatically); - obj.setProperty("firstFrame", details.firstFrame); - obj.setProperty("lastFrame", details.lastFrame); - obj.setProperty("running", details.running); - obj.setProperty("currentFrame", details.currentFrame); - obj.setProperty("allowTranslation", details.allowTranslation); - return obj; -} - -void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& details) { - // nothing for now... -} - -QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) { - return engine->newQObject(in, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); -} - -void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) { - out = qobject_cast(value.toQObject()); -} - -QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) { - // QScriptValueList result; - QScriptValue result = engine->newArray(); - int i = 0; - foreach(MeshProxy* const meshProxy, in) { - result.setProperty(i++, meshToScriptValue(engine, meshProxy)); - } - return result; -} - -void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out) { - QScriptValueIterator itr(value); - - qDebug() << "in meshesFromScriptValue, value.length =" << value.property("length").toInt32(); - - while (itr.hasNext()) { - itr.next(); - MeshProxy* meshProxy = qscriptvalue_cast(itr.value()); - if (meshProxy) { - out.append(meshProxy); - } else { - qDebug() << "null meshProxy"; - } - } -} - - -/**jsdoc - * A triangle in a mesh. - * @typedef {object} MeshFace - * @property {number[]} vertices - The indexes of the three vertices that make up the face. - */ -QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace) { - QScriptValue obj = engine->newObject(); - obj.setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices)); - return obj; -} - -void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult) { - qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices); -} - -QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector& vector) { - QScriptValue array = engine->newArray(); - for (int i = 0; i < vector.size(); i++) { - array.setProperty(i, meshFaceToScriptValue(engine, vector.at(i))); - } - return array; -} - -void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector& result) { - int length = array.property("length").toInteger(); - result.clear(); - - for (int i = 0; i < length; i++) { - MeshFace meshFace = MeshFace(); - meshFaceFromScriptValue(array.property(i), meshFace); - result << meshFace; - } -} - QVariantMap parseTexturesToMap(QString newTextures, const QVariantMap& defaultTextures) { // If textures are unset, revert to original textures if (newTextures.isEmpty()) { @@ -1392,11 +569,3 @@ QVariantMap parseTexturesToMap(QString newTextures, const QVariantMap& defaultTe return toReturn; } - -QScriptValue stencilMaskModeToScriptValue(QScriptEngine* engine, const StencilMaskMode& stencilMode) { - return engine->newVariant((int)stencilMode); -} - -void stencilMaskModeFromScriptValue(const QScriptValue& object, StencilMaskMode& stencilMode) { - stencilMode = StencilMaskMode(object.toVariant().toInt()); -} \ No newline at end of file diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 49a73d40c27..8a731d147ef 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -12,7 +12,6 @@ #ifndef hifi_RegisteredMetaTypes_h #define hifi_RegisteredMetaTypes_h -#include #include #include @@ -43,8 +42,6 @@ Q_DECLARE_METATYPE(AACube) Q_DECLARE_METATYPE(std::function); Q_DECLARE_METATYPE(std::function); -void registerMetaTypes(QScriptEngine* engine); - // Mat4 /**jsdoc * A 4 x 4 matrix, typically containing a scale, rotation, and translation transform. See also the {@link Mat4(0)|Mat4} object. @@ -67,9 +64,6 @@ void registerMetaTypes(QScriptEngine* engine); * @property {number} r2c3 - Row 2, column 3 value. * @property {number} r3c3 - Row 3, column 3 value. */ -QScriptValue mat4toScriptValue(QScriptEngine* engine, const glm::mat4& mat4); -void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4); - QVariant mat4ToVariant(const glm::mat4& mat4); glm::mat4 mat4FromVariant(const QVariant& object, bool& valid); glm::mat4 mat4FromVariant(const QVariant& object); @@ -88,9 +82,6 @@ glm::mat4 mat4FromVariant(const QVariant& object); * var color = Entities.getEntityProperties().materialMappingPos; // { x: 0.7, y: 0.7 } * color.v = 0.8; // { x: 0.7, y: 0.8 } */ -QScriptValue vec2ToScriptValue(QScriptEngine* engine, const glm::vec2& vec2); -void vec2FromScriptValue(const QScriptValue& object, glm::vec2& vec2); - QVariant vec2ToVariant(const glm::vec2& vec2); glm::vec2 vec2FromVariant(const QVariant& object, bool& valid); glm::vec2 vec2FromVariant(const QVariant& object); @@ -115,10 +106,6 @@ glm::vec2 vec2FromVariant(const QVariant& object); * Entities.editEntity(, { position: "red"}); // { x: 255, y: 0, z: 0 } * Entities.editEntity(, { position: "#00FF00"}); // { x: 0, y: 255, z: 0 } */ -QScriptValue vec3ToScriptValue(QScriptEngine* engine, const glm::vec3& vec3); -QScriptValue vec3ColorToScriptValue(QScriptEngine* engine, const glm::vec3& vec3); -void vec3FromScriptValue(const QScriptValue& object, glm::vec3& vec3); - QVariant vec3toVariant(const glm::vec3& vec3); glm::vec3 vec3FromVariant(const QVariant &object, bool& valid); glm::vec3 vec3FromVariant(const QVariant &object); @@ -161,10 +148,6 @@ glm::vec3 vec3FromVariant(const QVariant &object); * Entities.editEntity(, { color: "red"}); // { red: 255, green: 0, blue: 0 } * Entities.editEntity(, { color: "#00FF00"}); // { red: 0, green: 255, blue: 0 } */ -QScriptValue u8vec3ToScriptValue(QScriptEngine* engine, const glm::u8vec3& vec3); -QScriptValue u8vec3ColorToScriptValue(QScriptEngine* engine, const glm::u8vec3& vec3); -void u8vec3FromScriptValue(const QScriptValue& object, glm::u8vec3& vec3); - QVariant u8vec3toVariant(const glm::u8vec3& vec3); QVariant u8vec3ColortoVariant(const glm::u8vec3& vec3); glm::u8vec3 u8vec3FromVariant(const QVariant &object, bool& valid); @@ -179,16 +162,11 @@ glm::u8vec3 u8vec3FromVariant(const QVariant &object); * @property {number} z - Z-coordinate of the vector. * @property {number} w - W-coordinate of the vector. */ -QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4); -void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4); QVariant vec4toVariant(const glm::vec4& vec4); glm::vec4 vec4FromVariant(const QVariant &object, bool& valid); glm::vec4 vec4FromVariant(const QVariant &object); // Quaternions -QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat); -void quatFromScriptValue(const QScriptValue &object, glm::quat& quat); - QVariant quatToVariant(const glm::quat& quat); glm::quat quatFromVariant(const QVariant &object, bool& isValid); glm::quat quatFromVariant(const QVariant &object); @@ -201,59 +179,14 @@ glm::quat quatFromVariant(const QVariant &object); * @property {number} width - Width of the rectangle. * @property {number} height - Height of the rectangle. */ -QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect); -void qRectFromScriptValue(const QScriptValue& object, QRect& rect); QRect qRectFromVariant(const QVariant& object, bool& isValid); QRect qRectFromVariant(const QVariant& object); QVariant qRectToVariant(const QRect& rect); -QScriptValue qRectFToScriptValue(QScriptEngine* engine, const QRectF& rect); -void qRectFFromScriptValue(const QScriptValue& object, QRectF& rect); QRectF qRectFFromVariant(const QVariant& object, bool& isValid); QRectF qRectFFromVariant(const QVariant& object); QVariant qRectFToVariant(const QRectF& rect); -// QColor -QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color); -void qColorFromScriptValue(const QScriptValue& object, QColor& color); - -QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url); -void qURLFromScriptValue(const QScriptValue& object, QUrl& url); - -// vector -Q_DECLARE_METATYPE(QVector) -QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector); -QScriptValue qVectorVec3ColorToScriptValue(QScriptEngine* engine, const QVector& vector); -void qVectorVec3FromScriptValue(const QScriptValue& array, QVector& vector); -QVector qVectorVec3FromScriptValue(const QScriptValue& array); - -// vector -Q_DECLARE_METATYPE(QVector) -QScriptValue qVectorQuatToScriptValue(QScriptEngine* engine, const QVector& vector); -void qVectorQuatFromScriptValue(const QScriptValue& array, QVector& vector); -QVector qVectorQuatFromScriptValue(const QScriptValue& array); - -// vector -QScriptValue qVectorBoolToScriptValue(QScriptEngine* engine, const QVector& vector); -void qVectorBoolFromScriptValue(const QScriptValue& array, QVector& vector); -QVector qVectorBoolFromScriptValue(const QScriptValue& array); - -// vector -QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector& vector); -void qVectorFloatFromScriptValue(const QScriptValue& array, QVector& vector); -QVector qVectorFloatFromScriptValue(const QScriptValue& array); - -// vector -QScriptValue qVectorIntToScriptValue(QScriptEngine* engine, const QVector& vector); -void qVectorIntFromScriptValue(const QScriptValue& array, QVector& vector); - -QScriptValue qVectorQUuidToScriptValue(QScriptEngine* engine, const QVector& vector); -void qVectorQUuidFromScriptValue(const QScriptValue& array, QVector& vector); -QVector qVectorQUuidFromScriptValue(const QScriptValue& array); - -QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube); -void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube); - // MathPicks also have to overide operator== for their type class MathPick { public: @@ -292,8 +225,6 @@ class PickRay : public MathPick { } }; Q_DECLARE_METATYPE(PickRay) -QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); -void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); /**jsdoc * The tip of a stylus. @@ -644,22 +575,6 @@ class Collision { glm::vec3 velocityChange; }; Q_DECLARE_METATYPE(Collision) -QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision); -void collisionFromScriptValue(const QScriptValue &object, Collision& collision); - -/**jsdoc - * UUIDs (Universally Unique IDentifiers) are used to uniquely identify entities, avatars, and the like. They are represented - * in JavaScript as strings in the format, "{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}", where the "n"s are - * hexadecimal digits. - * @typedef {string} Uuid - */ -//Q_DECLARE_METATYPE(QUuid) // don't need to do this for QUuid since it's already a meta type -QScriptValue quuidToScriptValue(QScriptEngine* engine, const QUuid& uuid); -void quuidFromScriptValue(const QScriptValue& object, QUuid& uuid); - -//Q_DECLARE_METATYPE(QSizeF) // Don't need to to this becase it's arleady a meta type -QScriptValue qSizeFToScriptValue(QScriptEngine* engine, const QSizeF& qSizeF); -void qSizeFFromScriptValue(const QScriptValue& object, QSizeF& qSizeF); class AnimationDetails { public: @@ -681,8 +596,6 @@ class AnimationDetails { bool allowTranslation; }; Q_DECLARE_METATYPE(AnimationDetails); -QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event); -void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& event); namespace graphics { class Mesh; @@ -733,12 +646,6 @@ class MeshProxyList : public QList {}; // typedef and using fight wi Q_DECLARE_METATYPE(MeshProxyList); -QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in); -void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out); - -QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in); -void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out); - class MeshFace { public: @@ -752,15 +659,8 @@ class MeshFace { Q_DECLARE_METATYPE(MeshFace) Q_DECLARE_METATYPE(QVector) -QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace); -void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult); -QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector& vector); -void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector& result); - QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures); Q_DECLARE_METATYPE(StencilMaskMode) -QScriptValue stencilMaskModeToScriptValue(QScriptEngine* engine, const StencilMaskMode& stencilMode); -void stencilMaskModeFromScriptValue(const QScriptValue& object, StencilMaskMode& stencilMode); #endif // hifi_RegisteredMetaTypes_h diff --git a/libraries/shared/src/ScriptValueUtils.cpp b/libraries/shared/src/ScriptValueUtils.cpp deleted file mode 100644 index e352c0546d9..00000000000 --- a/libraries/shared/src/ScriptValueUtils.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// -// ScriptValueUtils.cpp -// libraries/shared/src -// -// Created by Anthony Thibault on 4/15/16. -// Copyright 2016 High Fidelity, Inc. -// -// Utilities for working with QtScriptValues -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "ScriptValueUtils.h" - -bool isListOfStrings(const QScriptValue& arg) { - if (!arg.isArray()) { - return false; - } - - auto lengthProperty = arg.property("length"); - if (!lengthProperty.isNumber()) { - return false; - } - - int length = lengthProperty.toInt32(); - for (int i = 0; i < length; i++) { - if (!arg.property(i).isString()) { - return false; - } - } - - return true; -} diff --git a/libraries/shared/src/ScriptValueUtils.h b/libraries/shared/src/ScriptValueUtils.h deleted file mode 100644 index dc2f41997b4..00000000000 --- a/libraries/shared/src/ScriptValueUtils.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// ScriptValueUtils.h -// libraries/shared/src -// -// Created by Anthony Thibault on 4/15/16. -// Copyright 2016 High Fidelity, Inc. -// -// Utilities for working with QtScriptValues -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_ScriptValueUtils_h -#define hifi_ScriptValueUtils_h - -#include - -bool isListOfStrings(const QScriptValue& value); - -#endif // #define hifi_ScriptValueUtils_h diff --git a/libraries/shared/src/VariantMapToScriptValue.h b/libraries/shared/src/VariantMapToScriptValue.h deleted file mode 100644 index 4b283671b43..00000000000 --- a/libraries/shared/src/VariantMapToScriptValue.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// VariantMapToScriptValue.h -// libraries/shared/src/ -// -// Created by Brad Hefta-Gaub on 12/6/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include - -QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine); -QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine); -QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine); diff --git a/libraries/shared/src/shared/MiniPromises.cpp b/libraries/shared/src/shared/MiniPromises.cpp index 21a3f44d50f..57b4496b96f 100644 --- a/libraries/shared/src/shared/MiniPromises.cpp +++ b/libraries/shared/src/shared/MiniPromises.cpp @@ -7,20 +7,5 @@ // #include "MiniPromises.h" -#include -#include int MiniPromise::metaTypeID = qRegisterMetaType("MiniPromise::Promise"); - -namespace { - void promiseFromScriptValue(const QScriptValue& object, MiniPromise::Promise& promise) { - Q_ASSERT(false); - } - QScriptValue promiseToScriptValue(QScriptEngine *engine, const MiniPromise::Promise& promise) { - return engine->newQObject(promise.get()); - } -} -void MiniPromise::registerMetaTypes(QObject* engine) { - auto scriptEngine = qobject_cast(engine); - qScriptRegisterMetaType(scriptEngine, promiseToScriptValue, promiseFromScriptValue); -} diff --git a/libraries/shared/src/shared/MiniPromises.h b/libraries/shared/src/shared/MiniPromises.h index 30b57ad7b84..e49bc48d18e 100644 --- a/libraries/shared/src/shared/MiniPromises.h +++ b/libraries/shared/src/shared/MiniPromises.h @@ -42,7 +42,6 @@ class MiniPromise : public QObject, public std::enable_shared_from_this; using Promise = std::shared_ptr; - static void registerMetaTypes(QObject* engine); static int metaTypeID; MiniPromise() {} diff --git a/libraries/shared/src/shared/ScriptInitializerMixin.h b/libraries/shared/src/shared/ScriptInitializerMixin.h index cefa33c2d3b..789606331d2 100644 --- a/libraries/shared/src/shared/ScriptInitializerMixin.h +++ b/libraries/shared/src/shared/ScriptInitializerMixin.h @@ -13,7 +13,6 @@ #include #include "../DependencyManager.h" -class QScriptEngine; class ScriptEngine; template class ScriptInitializerMixin { @@ -36,11 +35,11 @@ template class ScriptInitializerMixin { std::list _scriptInitializers; }; -class ScriptInitializers : public ScriptInitializerMixin, public Dependency { +class ScriptInitializers : public ScriptInitializerMixin, public Dependency { public: - // Lightweight `QScriptEngine*` initializer (only depends on built-in Qt components) + // Lightweight `ScriptEngine*` initializer (only depends on built-in Qt components) // example registration: - // eg: [&](QScriptEngine* engine) { + // eg: [&](ScriptEngine* engine) { // engine->globalObject().setProperties("API", engine->newQObject(...instance...)) // }; }; diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 3625bd4f3e7..66a17509e3e 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,6 +1,8 @@ set(TARGET_NAME ui) -setup_hifi_library(OpenGL Multimedia Network Qml Quick Script WebChannel WebSockets XmlPatterns ${PLATFORM_QT_COMPONENTS}) -link_hifi_libraries(shared networking qml gl audio audio-client plugins pointers) +setup_hifi_library(OpenGL Multimedia Network Qml Quick WebChannel WebSockets XmlPatterns ${PLATFORM_QT_COMPONENTS}) +link_hifi_libraries(shared networking qml gl audio audio-client plugins pointers script-engine) +include_hifi_library_headers(animation) +include_hifi_library_headers(entities) include_hifi_library_headers(controllers) # Required for some low level GL interaction in the OffscreenQMLSurface diff --git a/libraries/ui/src/QmlFragmentClass.cpp b/libraries/ui/src/QmlFragmentClass.cpp index 1219094afcb..163d5e2ca70 100644 --- a/libraries/ui/src/QmlFragmentClass.cpp +++ b/libraries/ui/src/QmlFragmentClass.cpp @@ -9,21 +9,23 @@ #include "QmlFragmentClass.h" #include -#include -#include #include +#include +#include +#include +#include std::mutex QmlFragmentClass::_mutex; -std::map QmlFragmentClass::_fragments; +std::map QmlFragmentClass::_fragments; QmlFragmentClass::QmlFragmentClass(bool restricted, QString id) : QmlWindowClass(restricted), qml(id) { } // Method called by Qt scripts to create a new bottom menu bar in Android -QScriptValue QmlFragmentClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) { +ScriptValuePointer QmlFragmentClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { #ifndef DISABLE_QML std::lock_guard guard(_mutex); - auto qml = context->argument(0).toVariant().toMap().value("qml"); + auto qml = context->argument(0)->toVariant().toMap().value("qml"); if (qml.isValid()) { // look up tabletId in the map. auto iter = _fragments.find(qml.toString()); @@ -33,7 +35,7 @@ QScriptValue QmlFragmentClass::internal_constructor(QScriptContext* context, QSc } } else { qWarning() << "QmlFragmentClass could not build instance " << qml; - return QScriptValue(); + return ScriptValuePointer(); } auto properties = parseArguments(context); @@ -45,12 +47,13 @@ QScriptValue QmlFragmentClass::internal_constructor(QScriptContext* context, QSc } else { retVal->initQml(properties); } - connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); - QScriptValue scriptObject = engine->newQObject(retVal); + auto manager = engine->manager(); + connect(manager, &ScriptManager::destroyed, retVal, &QmlWindowClass::deleteLater); + ScriptValuePointer scriptObject = engine->newQObject(retVal); _fragments[qml.toString()] = scriptObject; return scriptObject; #else - return QScriptValue(); + return ScriptValuePointer(); #endif } diff --git a/libraries/ui/src/QmlFragmentClass.h b/libraries/ui/src/QmlFragmentClass.h index ea80b2bd13e..67a4ffe1ab6 100644 --- a/libraries/ui/src/QmlFragmentClass.h +++ b/libraries/ui/src/QmlFragmentClass.h @@ -10,18 +10,24 @@ #define hifi_ui_QmlFragmentClass_h #include "QmlWindowClass.h" +#include + +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class QmlFragmentClass : public QmlWindowClass { Q_OBJECT private: - static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted); + static ScriptValuePointer internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); public: - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) { + static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine) { return internal_constructor(context, engine, false); } - static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){ + static ScriptValuePointer restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ return internal_constructor(context, engine, true); } @@ -46,7 +52,7 @@ public slots: QString qmlSource() const override { return qml; } static std::mutex _mutex; - static std::map _fragments; + static std::map _fragments; private: QString qml; diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index c7851d416fe..e86355a3442 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -10,8 +10,9 @@ #include -#include -#include +#include +#include +#include #include @@ -19,7 +20,7 @@ static const char* const URL_PROPERTY = "source"; static const char* const SCRIPT_PROPERTY = "scriptUrl"; // Method called by Qt scripts to create a new web window in the overlay -QScriptValue QmlWebWindowClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) { +ScriptValuePointer QmlWebWindowClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { auto properties = parseArguments(context); QmlWebWindowClass* retVal = new QmlWebWindowClass(restricted); Q_ASSERT(retVal); @@ -29,7 +30,8 @@ QScriptValue QmlWebWindowClass::internal_constructor(QScriptContext* context, QS } else { retVal->initQml(properties); } - connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); + auto manager = engine->manager(); + connect(manager, &ScriptManager::destroyed, retVal, &QmlWindowClass::deleteLater); return engine->newQObject(retVal); } diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index feca1486140..4837f792a02 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -9,8 +9,15 @@ #ifndef hifi_ui_QmlWebWindowClass_h #define hifi_ui_QmlWebWindowClass_h +#include + #include "QmlWindowClass.h" +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + /**jsdoc * A OverlayWebWindow displays an HTML window inside Interface. * @@ -142,15 +149,15 @@ class QmlWebWindowClass : public QmlWindowClass { Q_PROPERTY(QString url READ getURL CONSTANT) private: - static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted); + static ScriptValuePointer internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); public: QmlWebWindowClass(bool restricted) : QmlWindowClass(restricted) {} - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) { + static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine) { return internal_constructor(context, engine, false); } - static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){ + static ScriptValuePointer restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ return internal_constructor(context, engine, true); } diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index ae2292dc09a..51d8a3b5a53 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -11,8 +11,6 @@ #include #include -#include -#include #include #include @@ -27,6 +25,10 @@ #include "OffscreenUi.h" #include "ui/types/HFWebEngineProfile.h" #include "ui/types/FileTypeProfile.h" +#include +#include +#include +#include static const char* const SOURCE_PROPERTY = "source"; static const char* const TITLE_PROPERTY = "title"; @@ -37,24 +39,24 @@ static const char* const VISIBILE_PROPERTY = "visible"; static const uvec2 MAX_QML_WINDOW_SIZE { 1280, 720 }; static const uvec2 MIN_QML_WINDOW_SIZE { 120, 80 }; -QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { +QVariantMap QmlWindowClass::parseArguments(ScriptContext* context) { const auto argumentCount = context->argumentCount(); QVariantMap properties; if (argumentCount > 1) { - if (!context->argument(0).isUndefined()) { - properties[TITLE_PROPERTY] = context->argument(0).toString(); + if (!context->argument(0)->isUndefined()) { + properties[TITLE_PROPERTY] = context->argument(0)->toString(); } - if (!context->argument(1).isUndefined()) { - properties[SOURCE_PROPERTY] = context->argument(1).toString(); + if (!context->argument(1)->isUndefined()) { + properties[SOURCE_PROPERTY] = context->argument(1)->toString(); } - if (context->argument(2).isNumber()) { - properties[WIDTH_PROPERTY] = context->argument(2).toInt32(); + if (context->argument(2)->isNumber()) { + properties[WIDTH_PROPERTY] = context->argument(2)->toInt32(); } - if (context->argument(3).isNumber()) { - properties[HEIGHT_PROPERTY] = context->argument(3).toInt32(); + if (context->argument(3)->isNumber()) { + properties[HEIGHT_PROPERTY] = context->argument(3)->toInt32(); } } else { - properties = context->argument(0).toVariant().toMap(); + properties = context->argument(0)->toVariant().toMap(); } QUrl url { properties[SOURCE_PROPERTY].toString() }; @@ -70,7 +72,7 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { // Method called by Qt scripts to create a new web window in the overlay -QScriptValue QmlWindowClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) { +ScriptValuePointer QmlWindowClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { auto properties = parseArguments(context); QmlWindowClass* retVal = new QmlWindowClass(restricted); Q_ASSERT(retVal); @@ -80,7 +82,8 @@ QScriptValue QmlWindowClass::internal_constructor(QScriptContext* context, QScri } else { retVal->initQml(properties); } - connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); + auto manager = engine->manager(); + connect(manager, &ScriptManager::destroyed, retVal, &QmlWindowClass::deleteLater); return engine->newQObject(retVal); } diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h index 3a2f202bd39..129caef9519 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -11,13 +11,15 @@ #include #include -#include +#include #include #include -class QScriptEngine; -class QScriptContext; +class ScriptContext; +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; /**jsdoc * A OverlayWindow displays a QML window inside Interface. @@ -53,13 +55,13 @@ class QmlWindowClass : public QObject { Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) private: - static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted); + static ScriptValuePointer internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); public: - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) { + static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine) { return internal_constructor(context, engine, false); } - static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){ + static ScriptValuePointer restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ return internal_constructor(context, engine, true); } @@ -345,8 +347,8 @@ protected slots: void qmlToScript(const QVariant& message); protected: - static QVariantMap parseArguments(QScriptContext* context); - static QScriptValue internalConstructor(QScriptContext* context, QScriptEngine* engine, + static QVariantMap parseArguments(ScriptContext* context); + static ScriptValuePointer internalConstructor(ScriptContext* context, ScriptEngine* engine, std::function function); virtual QString qmlSource() const { return "QmlWindow.qml"; } diff --git a/libraries/ui/src/ui/QmlWrapper.h b/libraries/ui/src/ui/QmlWrapper.h index d77e45c9dc0..b768f3c262d 100644 --- a/libraries/ui/src/ui/QmlWrapper.h +++ b/libraries/ui/src/ui/QmlWrapper.h @@ -11,8 +11,11 @@ #include #include -#include -#include +#include + +class ScriptEngine; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; class QmlWrapper : public QObject { Q_OBJECT @@ -29,16 +32,16 @@ class QmlWrapper : public QObject { }; template -QScriptValue wrapperToScriptValue(QScriptEngine* engine, T* const &in) { +ScriptValuePointer wrapperToScriptValue(ScriptEngine* engine, T* const &in) { if (!in) { return engine->undefinedValue(); } - return engine->newQObject(in, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); + return engine->newQObject(in, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); } template -void wrapperFromScriptValue(const QScriptValue& value, T* &out) { - out = qobject_cast(value.toQObject()); +void wrapperFromScriptValue(const ScriptValuePointer& value, T* &out) { + out = qobject_cast(value->toQObject()); } #endif \ No newline at end of file diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index 5468ee18c30..9b7c0ebe703 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -18,10 +18,6 @@ #include #include -#include -#include -#include - #include #include diff --git a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp index d01b538004a..05b1804f87b 100644 --- a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp +++ b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp @@ -10,32 +10,32 @@ #include #include -#include -#include +#include +#include #include #include "../OffscreenUi.h" -QScriptValue toolbarToScriptValue(QScriptEngine* engine, ToolbarProxy* const &in) { +ScriptValuePointer toolbarToScriptValue(ScriptEngine* engine, ToolbarProxy* const &in) { if (!in) { return engine->undefinedValue(); } - return engine->newQObject(in, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); + return engine->newQObject(in, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); } -void toolbarFromScriptValue(const QScriptValue& value, ToolbarProxy* &out) { - out = qobject_cast(value.toQObject()); +void toolbarFromScriptValue(const ScriptValuePointer& value, ToolbarProxy* &out) { + out = qobject_cast(value->toQObject()); } -QScriptValue toolbarButtonToScriptValue(QScriptEngine* engine, ToolbarButtonProxy* const &in) { +ScriptValuePointer toolbarButtonToScriptValue(ScriptEngine* engine, ToolbarButtonProxy* const &in) { if (!in) { return engine->undefinedValue(); } - return engine->newQObject(in, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); + return engine->newQObject(in, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); } -void toolbarButtonFromScriptValue(const QScriptValue& value, ToolbarButtonProxy* &out) { - out = qobject_cast(value.toQObject()); +void toolbarButtonFromScriptValue(const ScriptValuePointer& value, ToolbarButtonProxy* &out) { + out = qobject_cast(value->toQObject()); } diff --git a/libraries/ui/src/ui/ToolbarScriptingInterface.h b/libraries/ui/src/ui/ToolbarScriptingInterface.h index 746ba2894e8..39695aca2ee 100644 --- a/libraries/ui/src/ui/ToolbarScriptingInterface.h +++ b/libraries/ui/src/ui/ToolbarScriptingInterface.h @@ -12,7 +12,6 @@ #include #include -#include #include #include "QmlWrapper.h" diff --git a/plugins/JSAPIExample/CMakeLists.txt b/plugins/JSAPIExample/CMakeLists.txt index a8fa0a1fd6a..02301654c85 100644 --- a/plugins/JSAPIExample/CMakeLists.txt +++ b/plugins/JSAPIExample/CMakeLists.txt @@ -1,3 +1,6 @@ set(TARGET_NAME JSAPIExample) setup_hifi_client_server_plugin(scripting) -link_hifi_libraries(shared plugins) +link_hifi_libraries(shared plugins script-engine) +include_hifi_library_headers(animation) +include_hifi_library_headers(entities) +include_hifi_library_headers(networking) diff --git a/plugins/JSAPIExample/src/JSAPIExample.cpp b/plugins/JSAPIExample/src/JSAPIExample.cpp index 91aa8bd32a5..05814e25817 100644 --- a/plugins/JSAPIExample/src/JSAPIExample.cpp +++ b/plugins/JSAPIExample/src/JSAPIExample.cpp @@ -18,12 +18,15 @@ #include #include #include -#include -#include #include // for ::settingsFilename() #include // for ::usecTimestampNow() #include +#include +#include +#include +#include +#include // NOTE: replace this with your own namespace when starting a new plugin (to avoid .so/.dll symbol clashes) namespace REPLACE_ME_WITH_UNIQUE_NAME { @@ -33,9 +36,9 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { QLoggingCategory logger { "jsapiexample" }; - inline QVariant raiseScriptingError(QScriptContext* context, const QString& message, const QVariant& returnValue = QVariant()) { + inline QVariant raiseScriptingError(ScriptContext* context, const QString& message, const QVariant& returnValue = QVariant()) { if (context) { - // when a QScriptContext is available throw an actual JS Exception (which can be caught using try/catch on JS side) + // when a ScriptContext is available throw an actual JS Exception (which can be caught using try/catch on JS side) context->throwError(message); } else { // otherwise just log the error @@ -46,7 +49,7 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { QObject* createScopedSettings(const QString& scope, QObject* parent, QString& error); - class JSAPIExample : public QObject, public QScriptable { + class JSAPIExample : public QObject, public Scriptable { Q_OBJECT Q_PLUGIN_METADATA(IID "JSAPIExample" FILE "plugin.json") Q_PROPERTY(QString version MEMBER _version CONSTANT) @@ -59,9 +62,9 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { return; } qCWarning(logger) << "registering w/ScriptInitializerMixin..." << scriptInit.data(); - scriptInit->registerScriptInitializer([this](QScriptEngine* engine) { - auto value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater); - engine->globalObject().setProperty(objectName(), value); + scriptInit->registerScriptInitializer([this](ScriptEngine* engine) { + auto value = engine->newQObject(this, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater); + engine->globalObject()->setProperty(objectName(), value); // qCDebug(logger) << "setGlobalInstance" << objectName() << engine->property("fileName"); }); // qCInfo(logger) << "plugin loaded" << qApp << toString() << QThread::currentThread(); @@ -69,7 +72,7 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { // NOTES: everything within the "public slots:" section below will be available from JS via overall plugin QObject // also, to demonstrate future-proofing JS API code, QVariant's are used throughout most of these examples -- - // which still makes them very Qt-specific, but avoids depending directly on deprecated QtScript/QScriptValue APIs. + // which still makes them very Qt-specific, but avoids depending directly on deprecated ScriptValuePointer APIs. // (as such this plugin class and its methods remain forward-compatible with other engines like QML's QJSEngine) public slots: @@ -145,7 +148,7 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { /** * Example of exposing a custom "managed" C++ QObject to JS - * The lifecycle of the created QObject* instance becomes managed by the invoking QScriptEngine -- + * The lifecycle of the created QObject* instance becomes managed by the invoking ScriptEngine -- * it will be automatically cleaned up once no longer reachable from any JS variables/closures. * @example access persistent settings stored in separate .json files * var settings = JSAPIExample.getScopedSettings("example"); @@ -156,18 +159,22 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { * print("all example::* keys", settings.allKeys()); * settings = null; // optional best pratice; allows the object to be reclaimed ASAP by the JS garbage collector */ - QScriptValue getScopedSettings(const QString& scope) { - auto engine = QScriptable::engine(); + ScriptValuePointer getScopedSettings(const QString& scope) { + auto engine = Scriptable::engine(); if (!engine) { - return QScriptValue::NullValue; + return ScriptValuePointer(); + } + auto manager = engine->manager(); + if (!manager) { + return ScriptValuePointer(); } QString error; - auto cppValue = createScopedSettings(scope, engine, error); + auto cppValue = createScopedSettings(scope, manager, error); if (!cppValue) { raiseScriptingError(context(), "error creating scoped settings instance: " + error); - return QScriptValue::NullValue; + return engine->nullValue(); } - return engine->newQObject(cppValue, QScriptEngine::ScriptOwnership, QScriptEngine::ExcludeDeleteLater); + return engine->newQObject(cppValue, ScriptEngine::ScriptOwnership, ScriptEngine::ExcludeDeleteLater); } private: diff --git a/plugins/hifiSdl2/CMakeLists.txt b/plugins/hifiSdl2/CMakeLists.txt index e1f0ee28d8b..16ce6f51b4a 100644 --- a/plugins/hifiSdl2/CMakeLists.txt +++ b/plugins/hifiSdl2/CMakeLists.txt @@ -16,6 +16,7 @@ if (NOT APPLE) link_libraries("-Wl,--allow-multiple-definition") endif() setup_hifi_plugin(Qml) - link_hifi_libraries(shared controllers ui plugins input-plugins script-engine) + link_hifi_libraries(shared controllers ui plugins input-plugins) + include_hifi_library_headers(script-engine) target_sdl2() endif() diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index 0b9358242dd..f8e818e7fd3 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -11,9 +11,10 @@ if ((WIN32 OR UNIX AND NOT APPLE) AND NOT USE_GLES) set(TARGET_NAME openvr) setup_hifi_plugin(Gui Qml Multimedia) link_hifi_libraries(shared task gl qml networking controllers ui - plugins display-plugins ui-plugins input-plugins script-engine + plugins display-plugins ui-plugins input-plugins audio-client render-utils graphics shaders gpu render material-networking model-networking model-baker hfm model-serializers ktx image procedural ${PLATFORM_GL_BACKEND}) include_hifi_library_headers(octree) + include_hifi_library_headers(script-engine) target_openvr() if (WIN32) diff --git a/scripts/system/request-service.js b/scripts/system/request-service.js index b57f2d4cd77..f51931bb3a7 100644 --- a/scripts/system/request-service.js +++ b/scripts/system/request-service.js @@ -14,7 +14,7 @@ // QML has its own XMLHttpRequest, but: // - npm request is easier to use. // - It is not easy to hack QML's XMLHttpRequest to use our MetaverseServer, and to supply the user's auth when contacting it. - // a. Our custom XMLHttpRequestClass object only works with QScriptEngine, not QML's javascript. + // a. Our custom XMLHttpRequestClass object only works with ScriptEngine, not QML's javascript. // b. We have hacked profiles that intercept requests to our MetavserseServer (providing the correct auth), but those // only work in QML WebEngineView. Setting up communication between ordinary QML and a hiddent WebEngineView is // tantamount to the following anyway, and would still have to duplicate the code from request.js. diff --git a/tests-manual/controllers/CMakeLists.txt b/tests-manual/controllers/CMakeLists.txt index 932826c8de1..c200e2fb9ca 100644 --- a/tests-manual/controllers/CMakeLists.txt +++ b/tests-manual/controllers/CMakeLists.txt @@ -3,7 +3,7 @@ if (NOT APPLE) set(TARGET_NAME controllers-test) # This is not a testcase -- just set it up as a regular hifi project -setup_hifi_project(Script Qml) +setup_hifi_project(Qml) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") setup_memory_debugger() diff --git a/tests-manual/entities/CMakeLists.txt b/tests-manual/entities/CMakeLists.txt index a6eed4f2344..1aede6ad6b0 100644 --- a/tests-manual/entities/CMakeLists.txt +++ b/tests-manual/entities/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME "entities-test") # This is not a testcase -- just set it up as a regular hifi project -setup_hifi_project(Network Script) +setup_hifi_project(Network) setup_memory_debugger() setup_thread_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") diff --git a/tests-manual/gpu-textures/CMakeLists.txt b/tests-manual/gpu-textures/CMakeLists.txt index d148b0cd21e..fcade688f95 100644 --- a/tests-manual/gpu-textures/CMakeLists.txt +++ b/tests-manual/gpu-textures/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME gpu-textures-tests) # This is not a testcase -- just set it up as a regular hifi project -setup_hifi_project(Quick Gui Script) +setup_hifi_project(Quick Gui) setup_memory_debugger() setup_thread_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") diff --git a/tests-manual/gpu/CMakeLists.txt b/tests-manual/gpu/CMakeLists.txt index dc7bfbe75e0..e72d1672942 100644 --- a/tests-manual/gpu/CMakeLists.txt +++ b/tests-manual/gpu/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME gpu-test) # This is not a testcase -- just set it up as a regular hifi project -setup_hifi_project(Quick Gui Script) +setup_hifi_project(Quick Gui) setup_memory_debugger() setup_thread_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index 287a3b73d87..49a031887d2 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -7,4 +7,4 @@ macro (setup_testcase_dependencies) package_libraries_for_deployment() endmacro () -setup_hifi_testcase(Script Network) +setup_hifi_testcase(Network) diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index 87e5350c8f8..f47e27226b4 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -6,4 +6,4 @@ macro (SETUP_TESTCASE_DEPENDENCIES) package_libraries_for_deployment() endmacro () -setup_hifi_testcase(Script) +setup_hifi_testcase() diff --git a/tools/oven/CMakeLists.txt b/tools/oven/CMakeLists.txt index 4f48570428b..95206d1ced6 100644 --- a/tools/oven/CMakeLists.txt +++ b/tools/oven/CMakeLists.txt @@ -3,6 +3,7 @@ set(TARGET_NAME oven) setup_hifi_project(Widgets Gui Concurrent) link_hifi_libraries(shared shaders image gpu ktx model-serializers hfm baking graphics networking procedural material-networking model-baker task) +include_hifi_library_headers(script-engine) setup_memory_debugger() setup_thread_debugger() From b52624c0e43f1e712473f22cfffd91df41e7a294 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 29 Aug 2021 21:01:40 -0700 Subject: [PATCH 03/34] working to clean up the QtScript implementation and move towards completion of the proxy interface --- .../script-engine-qtscript/CMakeLists.txt | 10 - .../src/BaseScriptEngine.cpp | 332 ------ .../src/BaseScriptEngine.h | 99 -- .../src/ScriptEngineQtScript.cpp | 493 -------- libraries/script-engine/CMakeLists.txt | 4 +- libraries/script-engine/src/ScriptContext.h | 11 +- libraries/script-engine/src/ScriptEngine.cpp | 67 ++ libraries/script-engine/src/ScriptEngine.h | 1 + .../script-engine/src/ScriptEngineCast.h | 2 + libraries/script-engine/src/ScriptManager.cpp | 69 +- libraries/script-engine/src/ScriptManager.h | 4 +- libraries/script-engine/src/ScriptValue.h | 2 + libraries/script-engine/src/Scriptable.cpp | 24 + .../src/qtscript/ArrayBufferClass.cpp | 180 +++ .../src/qtscript}/ArrayBufferClass.h | 0 .../src/qtscript}/ArrayBufferPrototype.cpp | 3 +- .../src/qtscript}/ArrayBufferPrototype.h | 0 .../src/qtscript}/ArrayBufferViewClass.cpp | 0 .../src/qtscript}/ArrayBufferViewClass.h | 0 .../src/qtscript}/DataViewClass.cpp | 0 .../src/qtscript}/DataViewClass.h | 0 .../src/qtscript}/DataViewPrototype.cpp | 4 +- .../src/qtscript}/DataViewPrototype.h | 0 .../src/qtscript/ScriptContextQtAgent.cpp | 73 ++ .../src/qtscript/ScriptContextQtAgent.h | 47 + .../src/qtscript/ScriptContextQtWrapper.cpp | 92 ++ .../src/qtscript/ScriptContextQtWrapper.h | 63 + .../src/qtscript/ScriptEngineQtScript.cpp | 1037 +++++++++++++++++ .../src/qtscript}/ScriptEngineQtScript.h | 164 ++- .../src/qtscript/ScriptProgramQtWrapper.cpp | 55 + .../src/qtscript/ScriptProgramQtWrapper.h | 55 + .../qtscript/ScriptValueIteratorQtWrapper.cpp | 33 + .../qtscript/ScriptValueIteratorQtWrapper.h | 41 + .../src/qtscript/ScriptValueQtWrapper.cpp | 216 ++++ .../src/qtscript/ScriptValueQtWrapper.h | 86 ++ .../src/qtscript}/TypedArrayPrototype.cpp | 0 .../src/qtscript}/TypedArrayPrototype.h | 0 .../src/qtscript}/TypedArrays.cpp | 0 .../src/qtscript}/TypedArrays.h | 0 39 files changed, 2242 insertions(+), 1025 deletions(-) delete mode 100644 libraries/script-engine-qtscript/CMakeLists.txt delete mode 100644 libraries/script-engine-qtscript/src/BaseScriptEngine.cpp delete mode 100644 libraries/script-engine-qtscript/src/BaseScriptEngine.h delete mode 100644 libraries/script-engine-qtscript/src/ScriptEngineQtScript.cpp create mode 100644 libraries/script-engine/src/ScriptEngine.cpp create mode 100644 libraries/script-engine/src/Scriptable.cpp create mode 100644 libraries/script-engine/src/qtscript/ArrayBufferClass.cpp rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/ArrayBufferClass.h (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/ArrayBufferPrototype.cpp (98%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/ArrayBufferPrototype.h (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/ArrayBufferViewClass.cpp (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/ArrayBufferViewClass.h (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/DataViewClass.cpp (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/DataViewClass.h (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/DataViewPrototype.cpp (98%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/DataViewPrototype.h (100%) create mode 100644 libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp create mode 100644 libraries/script-engine/src/qtscript/ScriptContextQtAgent.h create mode 100644 libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp create mode 100644 libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h create mode 100644 libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/ScriptEngineQtScript.h (66%) create mode 100644 libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp create mode 100644 libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h create mode 100644 libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp create mode 100644 libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h create mode 100644 libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp create mode 100644 libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/TypedArrayPrototype.cpp (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/TypedArrayPrototype.h (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/TypedArrays.cpp (100%) rename libraries/{script-engine-qtscript/src => script-engine/src/qtscript}/TypedArrays.h (100%) diff --git a/libraries/script-engine-qtscript/CMakeLists.txt b/libraries/script-engine-qtscript/CMakeLists.txt deleted file mode 100644 index 65a80d0ff34..00000000000 --- a/libraries/script-engine-qtscript/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -set(TARGET_NAME script-engine-qtscript) -# FIXME Move undo scripting interface to application and remove Widgets -setup_hifi_library(Gui Script ScriptTools) - -link_hifi_libraries() -include_hifi_library_headers(animation) -include_hifi_library_headers(entities) -include_hifi_library_headers(networking) -include_hifi_library_headers(shared) -include_hifi_library_headers(script-engine) \ No newline at end of file diff --git a/libraries/script-engine-qtscript/src/BaseScriptEngine.cpp b/libraries/script-engine-qtscript/src/BaseScriptEngine.cpp deleted file mode 100644 index 6e815174735..00000000000 --- a/libraries/script-engine-qtscript/src/BaseScriptEngine.cpp +++ /dev/null @@ -1,332 +0,0 @@ -// -// BaseScriptEngine.cpp -// libraries/script-engine/src -// -// Created by Timothy Dedischew on 02/01/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "BaseScriptEngine.h" -#include "SharedLogging.h" - -#include -#include -#include -#include -#include -#include - -#include "Profile.h" - -bool BaseScriptEngine::IS_THREADSAFE_INVOCATION(const QThread *thread, const QString& method) { - if (QThread::currentThread() == thread) { - return true; - } - qCCritical(shared) << QString("Scripting::%1 @ %2 -- ignoring thread-unsafe call from %3") - .arg(method).arg(thread ? thread->objectName() : "(!thread)").arg(QThread::currentThread()->objectName()); - qCDebug(shared) << "(please resolve on the calling side by using invokeMethod, executeOnScriptThread, etc.)"; - Q_ASSERT(false); - return false; -} - -// engine-aware JS Error copier and factory -QScriptValue BaseScriptEngine::makeError(const QScriptValue& _other, const QString& type) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return unboundNullValue(); - } - auto other = _other; - if (other.isString()) { - other = newObject(); - other.setProperty("message", _other.toString()); - } - auto proto = globalObject().property(type); - if (!proto.isFunction()) { - proto = globalObject().property(other.prototype().property("constructor").property("name").toString()); - } - if (!proto.isFunction()) { -#ifdef DEBUG_JS_EXCEPTIONS - qCDebug(shared) << "BaseScriptEngine::makeError -- couldn't find constructor for" << type << " -- using Error instead"; -#endif - proto = globalObject().property("Error"); - } - if (other.engine() != this) { - // JS Objects are parented to a specific script engine instance - // -- this effectively ~clones it locally by routing through a QVariant and back - other = toScriptValue(other.toVariant()); - } - // ~ var err = new Error(other.message) - auto err = proto.construct(QScriptValueList({other.property("message")})); - - // transfer over any existing properties - QScriptValueIterator it(other); - while (it.hasNext()) { - it.next(); - err.setProperty(it.name(), it.value()); - } - return err; -} - -// check syntax and when there are issues returns an actual "SyntaxError" with the details -QScriptValue BaseScriptEngine::lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return unboundNullValue(); - } - const auto syntaxCheck = checkSyntax(sourceCode); - if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { - auto err = globalObject().property("SyntaxError") - .construct(QScriptValueList({syntaxCheck.errorMessage()})); - err.setProperty("fileName", fileName); - err.setProperty("lineNumber", syntaxCheck.errorLineNumber()); - err.setProperty("expressionBeginOffset", syntaxCheck.errorColumnNumber()); - err.setProperty("stack", currentContext()->backtrace().join(ScriptManager::SCRIPT_BACKTRACE_SEP)); - { - const auto error = syntaxCheck.errorMessage(); - const auto line = QString::number(syntaxCheck.errorLineNumber()); - const auto column = QString::number(syntaxCheck.errorColumnNumber()); - // for compatibility with legacy reporting - const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, fileName, line, column); - err.setProperty("formatted", message); - } - return err; - } - return QScriptValue(); -} - -// this pulls from the best available information to create a detailed snapshot of the current exception -QScriptValue BaseScriptEngine::cloneUncaughtException(const QString& extraDetail) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return unboundNullValue(); - } - if (!hasUncaughtException()) { - return unboundNullValue(); - } - auto exception = uncaughtException(); - // ensure the error object is engine-local - auto err = makeError(exception); - - // not sure why Qt does't offer uncaughtExceptionFileName -- but the line number - // on its own is often useless/wrong if arbitrarily married to a filename. - // when the error object already has this info, it seems to be the most reliable - auto fileName = exception.property("fileName").toString(); - auto lineNumber = exception.property("lineNumber").toInt32(); - - // the backtrace, on the other hand, seems most reliable taken from uncaughtExceptionBacktrace - auto backtrace = uncaughtExceptionBacktrace(); - if (backtrace.isEmpty()) { - // fallback to the error object - backtrace = exception.property("stack").toString().split(ScriptManager::SCRIPT_BACKTRACE_SEP); - } - // the ad hoc "detail" property can be used now to embed additional clues - auto detail = exception.property("detail").toString(); - if (detail.isEmpty()) { - detail = extraDetail; - } else if (!extraDetail.isEmpty()) { - detail += "(" + extraDetail + ")"; - } - if (lineNumber <= 0) { - lineNumber = uncaughtExceptionLineNumber(); - } - if (fileName.isEmpty()) { - // climb the stack frames looking for something useful to display - for (auto c = currentContext(); c && fileName.isEmpty(); c = c->parentContext()) { - QScriptContextInfo info { c }; - if (!info.fileName().isEmpty()) { - // take fileName:lineNumber as a pair - fileName = info.fileName(); - lineNumber = info.lineNumber(); - if (backtrace.isEmpty()) { - backtrace = c->backtrace(); - } - break; - } - } - } - err.setProperty("fileName", fileName); - err.setProperty("lineNumber", lineNumber ); - err.setProperty("detail", detail); - err.setProperty("stack", backtrace.join(ScriptManager::SCRIPT_BACKTRACE_SEP)); - -#ifdef DEBUG_JS_EXCEPTIONS - err.setProperty("_fileName", exception.property("fileName").toString()); - err.setProperty("_stack", uncaughtExceptionBacktrace().join(SCRIPT_BACKTRACE_SEP)); - err.setProperty("_lineNumber", uncaughtExceptionLineNumber()); -#endif - return err; -} - -bool BaseScriptEngine::raiseException(const QScriptValue& exception) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return false; - } - if (currentContext()) { - // we have an active context / JS stack frame so throw the exception per usual - currentContext()->throwValue(makeError(exception)); - return true; - } else { - // we are within a pure C++ stack frame (ie: being called directly by other C++ code) - // in this case no context information is available so just emit the exception for reporting - emit unhandledException(makeError(exception)); - } - return false; -} - -bool BaseScriptEngine::maybeEmitUncaughtException(const QString& debugHint) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return false; - } - if (!isEvaluating() && hasUncaughtException()) { - emit unhandledException(cloneUncaughtException(debugHint)); - clearExceptions(); - return true; - } - return false; -} - -QScriptValue BaseScriptEngine::evaluateInClosure(const QScriptValue& closure, const QScriptProgram& program) { - PROFILE_RANGE(script, "evaluateInClosure"); - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return unboundNullValue(); - } - const auto fileName = program.fileName(); - const auto shortName = QUrl(fileName).fileName(); - - QScriptValue result; - QScriptValue oldGlobal; - auto global = closure.property("global"); - if (global.isObject()) { -#ifdef DEBUG_JS - qCDebug(shared) << " setting global = closure.global" << shortName; -#endif - oldGlobal = globalObject(); - setGlobalObject(global); - } - - auto context = pushContext(); - - auto thiz = closure.property("this"); - if (thiz.isObject()) { -#ifdef DEBUG_JS - qCDebug(shared) << " setting this = closure.this" << shortName; -#endif - context->setThisObject(thiz); - } - - context->pushScope(closure); -#ifdef DEBUG_JS - qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName); -#endif - { - result = BaseScriptEngine::evaluate(program); - if (hasUncaughtException()) { - auto err = cloneUncaughtException(__FUNCTION__); -#ifdef DEBUG_JS_EXCEPTIONS - qCWarning(shared) << __FUNCTION__ << "---------- hasCaught:" << err.toString() << result.toString(); - err.setProperty("_result", result); -#endif - result = err; - } - } -#ifdef DEBUG_JS - qCDebug(shared) << QString("[%1] //evaluateInClosure %2").arg(isEvaluating()).arg(shortName); -#endif - popContext(); - - if (oldGlobal.isValid()) { -#ifdef DEBUG_JS - qCDebug(shared) << " restoring global" << shortName; -#endif - setGlobalObject(oldGlobal); - } - - return result; -} - -// Lambda -QScriptValue BaseScriptEngine::newLambdaFunction(std::function operation, const QScriptValue& data, const QScriptEngine::ValueOwnership& ownership) { - auto lambda = new Lambda(this, operation, data); - auto object = newQObject(lambda, ownership); - auto call = object.property("call"); - call.setPrototype(object); // context->callee().prototype() === Lambda QObject - call.setData(data); // context->callee().data() will === data param - return call; -} -QString Lambda::toString() const { - return QString("[Lambda%1]").arg(data.isValid() ? " " + data.toString() : data.toString()); -} - -Lambda::~Lambda() { -#ifdef DEBUG_JS_LAMBDA_FUNCS - qDebug() << "~Lambda" << "this" << this; -#endif -} - -Lambda::Lambda(QScriptEngine *engine, std::function operation, QScriptValue data) - : engine(engine), operation(operation), data(data) { -#ifdef DEBUG_JS_LAMBDA_FUNCS - qDebug() << "Lambda" << data.toString(); -#endif -} -QScriptValue Lambda::call() { - if (!BaseScriptEngine::IS_THREADSAFE_INVOCATION(engine->thread(), __FUNCTION__)) { - return BaseScriptEngine::unboundNullValue(); - } - return operation(engine->currentContext(), engine); -} - -QScriptValue makeScopedHandlerObject(QScriptValue scopeOrCallback, QScriptValue methodOrName) { - auto engine = scopeOrCallback.engine(); - if (!engine) { - return scopeOrCallback; - } - auto scope = QScriptValue(); - auto callback = scopeOrCallback; - if (scopeOrCallback.isObject()) { - if (methodOrName.isString()) { - scope = scopeOrCallback; - callback = scope.property(methodOrName.toString()); - } else if (methodOrName.isFunction()) { - scope = scopeOrCallback; - callback = methodOrName; - } else if (!methodOrName.isValid()) { - // instantiate from an existing scoped handler object - if (scopeOrCallback.property("callback").isFunction()) { - scope = scopeOrCallback.property("scope"); - callback = scopeOrCallback.property("callback"); - } - } - } - auto handler = engine->newObject(); - handler.setProperty("scope", scope); - handler.setProperty("callback", callback); - return handler; -} - -QScriptValue callScopedHandlerObject(QScriptValue handler, QScriptValue err, QScriptValue result) { - return handler.property("callback").call(handler.property("scope"), QScriptValueList({ err, result })); -} - -#ifdef DEBUG_JS -void BaseScriptEngine::_debugDump(const QString& header, const QScriptValue& object, const QString& footer) { - if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { - return; - } - if (!header.isEmpty()) { - qCDebug(shared) << header; - } - if (!object.isObject()) { - qCDebug(shared) << "(!isObject)" << object.toVariant().toString() << object.toString(); - return; - } - QScriptValueIterator it(object); - while (it.hasNext()) { - it.next(); - qCDebug(shared) << it.name() << ":" << it.value().toString(); - } - if (!footer.isEmpty()) { - qCDebug(shared) << footer; - } -} -#endif diff --git a/libraries/script-engine-qtscript/src/BaseScriptEngine.h b/libraries/script-engine-qtscript/src/BaseScriptEngine.h deleted file mode 100644 index 9e78c1239cd..00000000000 --- a/libraries/script-engine-qtscript/src/BaseScriptEngine.h +++ /dev/null @@ -1,99 +0,0 @@ -// -// BaseScriptEngine.h -// libraries/script-engine/src -// -// Created by Timothy Dedischew on 02/01/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_BaseScriptEngine_h -#define hifi_BaseScriptEngine_h - -#include -#include -#include - -class ScriptEngineQtScript; -using ScriptEngineQtScriptPointer = QSharedPointer; - -// common base class for extending QScriptEngine itself -class BaseScriptEngine : public QScriptEngine, public QEnableSharedFromThis { - Q_OBJECT -public: - // threadsafe "unbound" version of QScriptEngine::nullValue() - static const QScriptValue unboundNullValue() { return QScriptValue(0, QScriptValue::NullValue); } - - BaseScriptEngine() {} - - /*@jsdoc - * @function Script.lintScript - * @param {string} sourceCode - Source code. - * @param {string} fileName - File name. - * @param {number} [lineNumber=1] - Line number. - * @returns {object} Object. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE QScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1); - - /*@jsdoc - * @function Script.makeError - * @param {object} [other] - Other. - * @param {string} [type="Error"] - Error. - * @returns {object} Object. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE QScriptValue makeError(const QScriptValue& other = QScriptValue(), const QString& type = "Error"); - - QScriptValue cloneUncaughtException(const QString& detail = QString()); - QScriptValue evaluateInClosure(const QScriptValue& locals, const QScriptProgram& program); - - // if there is a pending exception and we are at the top level (non-recursive) stack frame, this emits and resets it - bool maybeEmitUncaughtException(const QString& debugHint = QString()); - - // if the currentContext() is valid then throw the passed exception; otherwise, immediately emit it. - // note: this is used in cases where C++ code might call into JS API methods directly - bool raiseException(const QScriptValue& exception); - - // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways - static bool IS_THREADSAFE_INVOCATION(const QThread *thread, const QString& method); -signals: - /*@jsdoc - * @function Script.signalHandlerException - * @param {object} exception - Exception. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - // Script.signalHandlerException is exposed by QScriptEngine. - -protected: - // like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues - // even though the context/engine parameters are redundant in most cases, the function signature matches `newFunction` - // anyway so that newLambdaFunction can be used to rapidly prototype / test utility APIs and then if becoming - // permanent more easily promoted into regular static newFunction scenarios. - QScriptValue newLambdaFunction(std::function operation, const QScriptValue& data = QScriptValue(), const QScriptEngine::ValueOwnership& ownership = QScriptEngine::AutoOwnership); - -#ifdef DEBUG_JS - static void _debugDump(const QString& header, const QScriptValue& object, const QString& footer = QString()); -#endif -}; - -// Lambda helps create callable QScriptValues out of std::functions: -// (just meant for use from within the script engine itself) -class Lambda : public QObject { - Q_OBJECT -public: - Lambda(QScriptEngine *engine, std::function operation, QScriptValue data); - ~Lambda(); - public slots: - QScriptValue call(); - QString toString() const; -private: - QScriptEngine* engine; - std::function operation; - QScriptValue data; -}; - -#endif // hifi_BaseScriptEngine_h diff --git a/libraries/script-engine-qtscript/src/ScriptEngineQtScript.cpp b/libraries/script-engine-qtscript/src/ScriptEngineQtScript.cpp deleted file mode 100644 index ee5d0ec8a75..00000000000 --- a/libraries/script-engine-qtscript/src/ScriptEngineQtScript.cpp +++ /dev/null @@ -1,493 +0,0 @@ -// -// ScriptEngineQtScript.cpp -// libraries/script-engine-qtscript/src -// -// Created by Brad Hefta-Gaub on 12/14/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "ScriptEngineQtScript.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include - -//#include -//#include -#include - -//#include "ArrayBufferViewClass.h" -//#include "AssetScriptingInterface.h" -//#include "BatchLoader.h" -//#include "BaseScriptEngine.h" -//#include "DataViewClass.h" -//#include "EventTypes.h" -//#include "FileScriptingInterface.h" // unzip project -//#include "MenuItemProperties.h" -//#include "ScriptAudioInjector.h" -//#include "ScriptAvatarData.h" -//#include "ScriptCache.h" -//#include "TypedArrays.h" -//#include "XMLHttpRequestClass.h" -//#include "WebSocketClass.h" -//#include "RecordingScriptingInterface.h" -//#include "ScriptEngines.h" -//#include "StackTestScriptingInterface.h" -//#include "ModelScriptingInterface.h" - -//#include - -//#include "../../midi/src/Midi.h" // FIXME why won't a simpler include work? -//#include "MIDIEvent.h" - -//#include "SettingHandle.h" -//#include -//#include -//#include - -static const int MAX_MODULE_ID_LENGTH { 4096 }; -static const int MAX_DEBUG_VALUE_LENGTH { 80 }; - -static const QScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = - QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects; -static const QScriptValue::PropertyFlags READONLY_PROP_FLAGS { QScriptValue::ReadOnly | QScriptValue::Undeletable }; -static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_PROP_FLAGS | QScriptValue::SkipInEnumeration }; - -static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; - -Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) -int functionSignatureMetaID = qRegisterMetaType(); - -int scriptEnginePointerMetaID = qRegisterMetaType(); - -static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { - // assemble the message by concatenating our arguments - QString message = ""; - for (int i = 0; i < context->argumentCount(); i++) { - if (i > 0) { - message += " "; - } - message += context->argument(i).toString(); - } - - // was this generated by a script engine? If we don't recognize it then send the message and exit - ScriptEngineQtScript* scriptEngine = qobject_cast(engine); - if (!scriptEngine) { - qCDebug(scriptengine_script, "%s", qUtf8Printable(message)); - return QScriptValue(); - } - - QString filename; - auto scriptManager = scriptEngine->manager(); - if (scriptManager) { - filename = scriptManager->getFilename(); - } - - // This message was sent by one of our script engines, let's try to see if we can find the source. - // Note that the first entry in the backtrace should be "print" and is somewhat useless to us - AbstractLoggerInterface* loggerInterface = AbstractLoggerInterface::get(); - if (loggerInterface && loggerInterface->showSourceDebugging()) { - QScriptContext* userContext = context; - while (userContext && QScriptContextInfo(userContext).functionType() == QScriptContextInfo::NativeFunction) { - userContext = userContext->parentContext(); - } - QString location; - if (userContext) { - QScriptContextInfo contextInfo(userContext); - QString fileName = contextInfo.fileName(); - int lineNumber = contextInfo.lineNumber(); - QString functionName = contextInfo.functionName(); - - location = functionName; - if (!fileName.isEmpty()) { - if (location.isEmpty()) { - location = fileName; - } else { - location = QString("%1 at %2").arg(location).arg(fileName); - } - } - if (lineNumber != -1) { - location = QString("%1:%2").arg(location).arg(lineNumber); - } - } - if (location.isEmpty()) { - location = filename; - } - - // give the script engine a chance to notify the system about this message - scriptEngine->print(message); - - // send the message to debug log - qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(location), qUtf8Printable(message)); - } else { - scriptEngine->print(message); - // prefix the script engine name to help disambiguate messages in the main debug log - qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(filename), qUtf8Printable(message)); - } - - return QScriptValue(); -} - -ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : - BaseScriptEngine(), - _manager(scriptManager), - _arrayBufferClass(new ArrayBufferClass(this)) -{ - if (_manager) { - connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { - if (Base::hasUncaughtException()) { - // the engine's uncaughtException() seems to produce much better stack traces here - emit _manager->unhandledException(Base::cloneUncaughtException("signalHandlerException")); - Base::clearExceptions(); - } else { - // ... but may not always be available -- so if needed we fallback to the passed exception - emit _manager->unhandledException(exception); - } - }, Qt::DirectConnection); - } - - setProcessEventsInterval(MSECS_PER_SECOND); -} - -bool ScriptEngineQtScript::isDebugMode() const { -#if defined(DEBUG) - return true; -#else - return false; -#endif -} - -ScriptEngineQtScript::~ScriptEngineQtScript() {} - -void ScriptEngineQtScript::disconnectNonEssentialSignals() { - disconnect(); - QThread* workerThread; - // Ensure the thread should be running, and does exist - if (_isRunning && _isThreaded && (workerThread = Base::thread())) { - connect(this, &QObject::destroyed, workerThread, &QThread::quit); - connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); - } -} - -void ScriptEngineQtScript::executeOnScriptThread(std::function function, const Qt::ConnectionType& type ) { - if (QThread::currentThread() != Base::thread()) { - QMetaObject::invokeMethod(this, "executeOnScriptThread", type, Q_ARG(std::function, function)); - return; - } - - function(); -} - -void ScriptEngineQtScript::registerValue(const QString& valueName, QScriptValue value) { - if (QThread::currentThread() != Base::thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; -#endif - QMetaObject::invokeMethod(this, "registerValue", - Q_ARG(const QString&, valueName), - Q_ARG(QScriptValue, value)); - return; - } - - QStringList pathToValue = valueName.split("."); - int partsToGo = pathToValue.length(); - QScriptValue partObject = globalObject(); - - for (const auto& pathPart : pathToValue) { - partsToGo--; - if (!partObject.property(pathPart).isValid()) { - if (partsToGo > 0) { - //QObject *object = new QObject; - QScriptValue partValue = newArray(); //newQObject(object, QScriptEngine::ScriptOwnership); - partObject.setProperty(pathPart, partValue); - } else { - partObject.setProperty(pathPart, value); - } - } - partObject = partObject.property(pathPart); - } -} - -void ScriptEngineQtScript::registerGlobalObject(const QString& name, QObject* object) { - if (QThread::currentThread() != Base::thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; -#endif - QMetaObject::invokeMethod(this, "registerGlobalObject", - Q_ARG(const QString&, name), - Q_ARG(QObject*, object)); - return; - } -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngineQtScript::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; -#endif - - if (!Base::globalObject().property(name).isValid()) { - if (object) { - QScriptValue value = Base::newQObject(object, QScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); - Base::globalObject().setProperty(name, value); - } else { - Base::globalObject().setProperty(name, QScriptValue()); - } - } -} - -void ScriptEngineQtScript::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { - if (QThread::currentThread() != Base::thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; -#endif - QMetaObject::invokeMethod(this, "registerFunction", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), - Q_ARG(int, numArguments)); - return; - } -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; -#endif - - QScriptValue scriptFun = Base::newFunction(functionSignature, numArguments); - Base::globalObject().setProperty(name, scriptFun); -} - -void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { - if (QThread::currentThread() != Base::thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; -#endif - QMetaObject::invokeMethod(this, "registerFunction", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), - Q_ARG(int, numArguments)); - return; - } -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; -#endif - - QScriptValue object = Base::globalObject().property(parent); - if (object.isValid()) { - QScriptValue scriptFun = Base::newFunction(functionSignature, numArguments); - object.setProperty(name, scriptFun); - } -} - -void ScriptEngineQtScript::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, - QScriptEngine::FunctionSignature setter, const QString& parent) { - if (QThread::currentThread() != Base::thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - " name:" << name << "parent:" << parent; -#endif - QMetaObject::invokeMethod(this, "registerGetterSetter", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, getter), - Q_ARG(QScriptEngine::FunctionSignature, setter), - Q_ARG(const QString&, parent)); - return; - } -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptEngineQtScript::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; -#endif - - QScriptValue setterFunction = Base::newFunction(setter, 1); - QScriptValue getterFunction = Base::newFunction(getter); - - if (!parent.isNull() && !parent.isEmpty()) { - QScriptValue object = Base::globalObject().property(parent); - if (object.isValid()) { - object.setProperty(name, setterFunction, QScriptValue::PropertySetter); - object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); - } - } else { - Base::globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); - Base::globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); - } -} - -// this is not redundant -- the version in BaseScriptEngine is specifically not Q_INVOKABLE -QScriptValue ScriptEngineQtScript::evaluateInClosure(const QScriptValue& closure, const QScriptProgram& program) { - return BaseScriptEngine::evaluateInClosure(closure, program); -} - -QScriptValue ScriptEngineQtScript::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) { - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { - return QScriptValue(); // bail early - } - - if (QThread::currentThread() != Base::thread()) { - QScriptValue result; -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; -#endif - BLOCKING_INVOKE_METHOD(this, "evaluate", - Q_RETURN_ARG(QScriptValue, result), - Q_ARG(const QString&, sourceCode), - Q_ARG(const QString&, fileName), - Q_ARG(int, lineNumber)); - return result; - } - - // Check syntax - auto syntaxError = Base::lintScript(sourceCode, fileName); - if (syntaxError.isError()) { - if (!Base::isEvaluating()) { - syntaxError.setProperty("detail", "evaluate"); - } - Base::raiseException(syntaxError); - Base::maybeEmitUncaughtException("lint"); - return syntaxError; - } - QScriptProgram program { sourceCode, fileName, lineNumber }; - if (program.isNull()) { - // can this happen? - auto err = Base::makeError("could not create QScriptProgram for " + fileName); - Base::raiseException(err); - Base::maybeEmitUncaughtException("compile"); - return err; - } - - QScriptValue result; - { - result = BaseScriptEngine::evaluate(program); - Base::maybeEmitUncaughtException("evaluate"); - } - return result; -} - -void ScriptEngineQtScript::updateMemoryCost(const qint64& deltaSize) { - if (deltaSize > 0) { - // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. -#if defined(Q_OS_WIN) || defined(Q_OS_MAC) - reportAdditionalMemoryCost(deltaSize); -#endif - } -} - -void ScriptEngineQtScript::print(const QString& message) { - QString filename; - auto scriptManager = manager(); - if (scriptManager) { - filename = scriptManager->getFilename(); - } - - emit printedMessage(message, filename); -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ScriptEngine implementation -/* -ScriptValuePointer ScriptEngineQtScript::globalObject() const { - return Base::globalObject(); -} - -ScriptManager* ScriptEngineQtScript::manager() const { -} - -ScriptValuePointer ScriptEngineQtScript::newArray(uint length) { - return Base::newArray(length); -} - -ScriptValuePointer ScriptEngineQtScript::newArrayBuffer(const QByteArray& message) { - QScriptValue data = Base::newVariant(QVariant::fromValue(message)); - QScriptValue ctor = Base::globalObject().property("ArrayBuffer"); - auto array = qscriptvalue_cast(ctor.data()); - if (!array) { - return undefinedValue() - } - return Base::newObject(array, data); -} - -ScriptValuePointer ScriptEngineQtScript::newObject() { - return Base::newObject(); -} - -ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, const QString& fileName) { -} - -ScriptValuePointer ScriptEngineQtScript::newQObject(QObject* obj) { -} - -ScriptValuePointer ScriptEngineQtScript::newValue(bool value) { -} - -ScriptValuePointer ScriptEngineQtScript::newValue(int value) { -} - -ScriptValuePointer ScriptEngineQtScript::newValue(uint value) { -} - -ScriptValuePointer ScriptEngineQtScript::newValue(double value) { -} - -ScriptValuePointer ScriptEngineQtScript::newValue(const QString& value) { -} - -ScriptValuePointer ScriptEngineQtScript::newValue(const QLatin1String& value) { -} - -ScriptValuePointer ScriptEngineQtScript::newValue(const char* value) { -} - -ScriptValuePointer ScriptEngineQtScript::newVariant(const QVariant& value) { -} - -ScriptValuePointer ScriptEngineQtScript::nullValue() { - return Base::nullValue(); -} - -void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype) { -} - -ScriptValuePointer ScriptEngineQtScript::undefinedValue() { - return Base::undefinedValue(); -} -*/ \ No newline at end of file diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index f26ce434822..ae4d16db52c 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,13 +1,13 @@ set(TARGET_NAME script-engine) # FIXME Move undo scripting interface to application and remove Widgets -setup_hifi_library(Network WebSockets) +setup_hifi_library(Gui Network Script ScriptTools WebSockets) target_zlib() if (NOT ANDROID) target_quazip() endif () -link_hifi_libraries(script-engine-qtscript shaders) +link_hifi_libraries(shaders) include_hifi_library_headers(animation) include_hifi_library_headers(audio) include_hifi_library_headers(avatars) diff --git a/libraries/script-engine/src/ScriptContext.h b/libraries/script-engine/src/ScriptContext.h index c3bec123c4e..dbdc6a5e370 100644 --- a/libraries/script-engine/src/ScriptContext.h +++ b/libraries/script-engine/src/ScriptContext.h @@ -14,11 +14,16 @@ #include #include +#include +class ScriptContext; class ScriptEngine; +class ScriptFunctionContext; class ScriptValue; -using ScriptValuePointer = QSharedPointer; +using ScriptContextPointer = QSharedPointer; +using ScriptFunctionContextPointer = QSharedPointer; using ScriptEnginePointer = QSharedPointer; +using ScriptValuePointer = QSharedPointer; class ScriptFunctionContext { public: @@ -43,8 +48,8 @@ class ScriptContext { virtual QStringList backtrace() const = 0; virtual ScriptValuePointer callee() const = 0; virtual ScriptEnginePointer engine() const = 0; - virtual ScriptFunctionContext* functionContext() const = 0; - virtual ScriptContext* parentContext() const = 0; + virtual ScriptFunctionContextPointer functionContext() const = 0; + virtual ScriptContextPointer parentContext() const = 0; virtual ScriptValuePointer thisObject() const = 0; virtual ScriptValuePointer throwError(const QString& text) = 0; virtual ScriptValuePointer throwValue(const ScriptValuePointer& value) = 0; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp new file mode 100644 index 00000000000..3a243da60f8 --- /dev/null +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -0,0 +1,67 @@ +// +// ScriptEngine.cpp +// libraries/script-engine/src +// +// Created by Brad Hefta-Gaub on 12/14/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptEngine.h" + +#include "ScriptEngineLogging.h" +#include "ScriptValue.h" +#include "qtscript/ScriptEngineQtScript.h" + +ScriptEnginePointer newScriptEngine(ScriptManager* manager) { + return QSharedPointer(new ScriptEngineQtScript(manager)); +} + +ScriptValuePointer makeScopedHandlerObject(ScriptValuePointer scopeOrCallback, ScriptValuePointer methodOrName) { + auto engine = scopeOrCallback->engine(); + if (!engine) { + return scopeOrCallback; + } + ScriptValuePointer scope; + ScriptValuePointer callback = scopeOrCallback; + if (scopeOrCallback->isObject()) { + if (methodOrName->isString()) { + scope = scopeOrCallback; + callback = scope->property(methodOrName->toString()); + } else if (methodOrName->isFunction()) { + scope = scopeOrCallback; + callback = methodOrName; + } else if (!methodOrName->isValid()) { + // instantiate from an existing scoped handler object + if (scopeOrCallback->property("callback")->isFunction()) { + scope = scopeOrCallback->property("scope"); + callback = scopeOrCallback->property("callback"); + } + } + } + auto handler = engine->newObject(); + handler->setProperty("scope", scope); + handler->setProperty("callback", callback); + return handler; +} + +ScriptValuePointer callScopedHandlerObject(ScriptValuePointer handler, ScriptValuePointer err, ScriptValuePointer result) { + return handler->property("callback")->call(handler->property("scope"), ScriptValueList({ err, result })); +} + +bool ScriptEngine::IS_THREADSAFE_INVOCATION(const QString& method) { + QThread* thread = this->thread(); + if (QThread::currentThread() == thread) { + return true; + } + qCCritical(scriptengine) << QString("Scripting::%1 @ %2 -- ignoring thread-unsafe call from %3") + .arg(method) + .arg(thread ? thread->objectName() : "(!thread)") + .arg(QThread::currentThread()->objectName()); + qCDebug(scriptengine) << "(please resolve on the calling side by using invokeMethod, executeOnScriptThread, etc.)"; + Q_ASSERT(false); + return false; +} diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 7144c91a374..2fd92343d7e 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -103,6 +103,7 @@ class ScriptEngine { virtual ScriptValuePointer uncaughtException() const = 0; virtual QStringList uncaughtExceptionBacktrace() const = 0; virtual int uncaughtExceptionLineNumber() const = 0; + virtual void updateMemoryCost(const qint64& deltaSize) = 0; public: // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h index ba56f920d4b..9a5c8a47c6a 100644 --- a/libraries/script-engine/src/ScriptEngineCast.h +++ b/libraries/script-engine/src/ScriptEngineCast.h @@ -14,6 +14,8 @@ // Object conversion helpers (copied from QScriptEngine) +#include + #include "ScriptEngine.h" #include "ScriptValue.h" diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index a0f7fe9ee3a..e2c083d3556 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -53,11 +53,9 @@ #include #include -#include "ArrayBufferViewClass.h" #include "AudioScriptingInterface.h" #include "AssetScriptingInterface.h" #include "BatchLoader.h" -#include "DataViewClass.h" #include "EventTypes.h" #include "FileScriptingInterface.h" // unzip project #include "MenuItemProperties.h" @@ -67,7 +65,6 @@ #include "ScriptContext.h" #include "ScriptEngineCast.h" #include "ScriptEngineLogging.h" -#include "TypedArrays.h" #include "XMLHttpRequestClass.h" #include "WebSocketClass.h" #include "RecordingScriptingInterface.h" @@ -133,8 +130,10 @@ static ScriptValuePointer debugPrint(ScriptContext* context, ScriptEngine* engin AbstractLoggerInterface* loggerInterface = AbstractLoggerInterface::get(); if (loggerInterface && loggerInterface->showSourceDebugging()) { ScriptContext* userContext = context; + ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan while (userContext && userContext->functionContext()->functionType() == ScriptFunctionContext::NativeFunction) { - userContext = userContext->parentContext(); + parentContext = userContext->parentContext(); + userContext = parentContext.data(); } QString location; if (userContext) { @@ -323,7 +322,7 @@ void ScriptManager::disconnectNonEssentialSignals() { connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); } } - +/* void ScriptManager::runDebuggable() { static QMenuBar* menuBar{ nullptr }; static QMenu* scriptDebugMenu { nullptr }; @@ -412,8 +411,7 @@ void ScriptManager::runDebuggable() { timer->start(10); } - - +*/ void ScriptManager::runInThread() { Q_ASSERT_X(!_isThreaded, "ScriptManager::runInThread()", "runInThread should not be called more than once"); @@ -656,9 +654,10 @@ static ScriptValuePointer scriptableResourceToScriptValue(ScriptEngine* engine, // in that case it would be too difficult to tell which one should track the memory, and // this serves the common case (use in a single script). auto data = resource->getResource(); - if (data && !resource->isInScript()) { + auto manager = engine->manager(); + if (data && manager && !resource->isInScript()) { resource->setInScript(true); - QObject::connect(data.data(), SIGNAL(updateSize(qint64)), engine, SLOT(updateMemoryCost(qint64))); + QObject::connect(data.data(), SIGNAL(updateSize(qint64)), manager, SLOT(updateMemoryCost(qint64))); } auto object = engine->newQObject( @@ -1059,6 +1058,11 @@ void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler(). } +bool ScriptManager::isStopped() const { + QSharedPointer scriptEngines(_scriptEngines); + return !scriptEngines || scriptEngines->isStopped(); +} + void ScriptManager::run() { if (QThread::currentThread() != qApp->thread() && _context == Context::CLIENT_SCRIPT) { // Flag that we're allowed to access local HTML files on UI created from C++ calls on this thread @@ -1070,8 +1074,7 @@ void ScriptManager::run() { auto name = filenameParts.size() > 0 ? filenameParts[filenameParts.size() - 1] : "unknown"; PROFILE_SET_THREAD_NAME("Script: " + name); - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { + if (isStopped()) { return; // bail early - avoid setting state in init(), as evaluate() will bail too } @@ -1324,21 +1327,13 @@ void ScriptManager::callAnimationStateHandler(ScriptValuePointer callback, AnimV } void ScriptManager::updateMemoryCost(const qint64& deltaSize) { - if (deltaSize > 0) { - // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. -#if defined(Q_OS_WIN) || defined(Q_OS_MAC) - reportAdditionalMemoryCost(deltaSize); -#endif - } + _engine->updateMemoryCost(deltaSize); } void ScriptManager::timerFired() { - { - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { - scriptWarningMessage("Script.timerFired() while shutting down is ignored... parent script:" + getFilename()); - return; // bail early - } + if (isStopped()) { + scriptWarningMessage("Script.timerFired() while shutting down is ignored... parent script:" + getFilename()); + return; // bail early } QTimer* callingTimer = reinterpret_cast(sender()); @@ -1388,8 +1383,7 @@ QObject* ScriptManager::setupTimerWithInterval(const ScriptValuePointer& functio } QObject* ScriptManager::setInterval(const ScriptValuePointer& function, int intervalMS) { - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { + if (isStopped()) { scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename()); return NULL; // bail early } @@ -1398,8 +1392,7 @@ QObject* ScriptManager::setInterval(const ScriptValuePointer& function, int inte } QObject* ScriptManager::setTimeout(const ScriptValuePointer& function, int timeoutMS) { - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { + if (isStopped()) { scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename()); return NULL; // bail early } @@ -1431,10 +1424,12 @@ QUrl ScriptManager::resolvePath(const QString& include) const { // to the first absolute URL in the JS scope chain QUrl parentURL; auto context = _engine->currentContext(); + ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan do { auto contextInfo = context->functionContext(); parentURL = QUrl(contextInfo->fileName()); - context = context->parentContext(); + parentContext = context->parentContext(); + context = parentContext.data(); } while (parentURL.isRelative() && context); if (parentURL.isRelative()) { @@ -1574,8 +1569,9 @@ ScriptValuePointer ScriptManager::currentModule() { auto jsRequire = _engine->globalObject()->property("Script")->property("require"); auto cache = jsRequire->property("cache"); auto candidate = ScriptValuePointer(); - for (auto c = _engine->currentContext(); c && !candidate->isObject(); c = c->parentContext()) { - auto contextInfo = c->functionContext(); + ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan + for (auto context = _engine->currentContext(); context && !candidate->isObject(); parentContext = context->parentContext(), context = parentContext.data()) { + auto contextInfo = context->functionContext(); candidate = cache->property(contextInfo->fileName()); } if (!candidate->isObject()) { @@ -1833,8 +1829,7 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return; } - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { + if (isStopped()) { scriptWarningMessage("Script.include() while shutting down is ignored... includeFiles:" + includeFiles.join(",") + "parent script:" + getFilename()); return; // bail early @@ -1928,8 +1923,7 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer } void ScriptManager::include(const QString& includeFile, ScriptValuePointer callback) { - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { + if (isStopped()) { scriptWarningMessage("Script.include() while shutting down is ignored... includeFile:" + includeFile + "parent script:" + getFilename()); return; // bail early @@ -1947,8 +1941,7 @@ void ScriptManager::load(const QString& loadFile) { if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return; } - QSharedPointer scriptEngines(_scriptEngines); - if (!scriptEngines || scriptEngines->isStopped()) { + if (isStopped()) { scriptWarningMessage("Script.load() while shutting down is ignored... loadFile:" + loadFile + "parent script:" + getFilename()); return; // bail early @@ -2785,3 +2778,7 @@ QString ScriptManager::formatException(const ScriptValuePointer& exception, bool } return result; } + +ScriptValuePointer ScriptManager::evaluate(const QString& program, const QString& fileName) { + return _engine->evaluate(program, fileName); +} diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index 3fd77800d3f..b7d01bcd267 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -177,10 +177,12 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi QString getFilename() const; - ScriptEnginePointer engine(); + inline ScriptEnginePointer engine() { return _engine; } QList getListOfEntityScriptIDs(); + bool isStopped() const; + /*@jsdoc * Stops and unloads the current script. *

Warning: If an assignment client script, the script gets restarted after stopping.

diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h index b3c90e8e444..67a8f8eb607 100644 --- a/libraries/script-engine/src/ScriptValue.h +++ b/libraries/script-engine/src/ScriptValue.h @@ -52,6 +52,7 @@ class ScriptValue { virtual ScriptValuePointer call(const ScriptValuePointer& thisObject, const ScriptValuePointer& arguments) = 0; virtual ScriptValuePointer construct(const ScriptValueList& args = ScriptValueList()) = 0; virtual ScriptValuePointer construct(const ScriptValuePointer& arguments) = 0; + virtual ScriptValuePointer data() const = 0; virtual ScriptEnginePointer engine() const = 0; inline bool equals(const ScriptValuePointer& other) const; inline bool isArray() const; @@ -68,6 +69,7 @@ class ScriptValue { virtual ScriptValueIteratorPointer newIterator() = 0; virtual ScriptValuePointer property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const = 0; virtual ScriptValuePointer property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const = 0; + virtual void setData(const ScriptValuePointer& val) = 0; virtual void setProperty(const QString& name, const ScriptValuePointer& value, const PropertyFlags& flags = KeepExistingFlags) = 0; diff --git a/libraries/script-engine/src/Scriptable.cpp b/libraries/script-engine/src/Scriptable.cpp new file mode 100644 index 00000000000..b205e6c2880 --- /dev/null +++ b/libraries/script-engine/src/Scriptable.cpp @@ -0,0 +1,24 @@ +// +// Scriptable.cpp +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/22/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Scriptable.h" + +#include + +static QThreadStorage ScriptContextStore; + +ScriptContext* Scriptable::context() { + return ScriptContextStore.localData(); +} + +void Scriptable::setContext(ScriptContext* context) { + ScriptContextStore.setLocalData(context); +} diff --git a/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp b/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp new file mode 100644 index 00000000000..3902096e52f --- /dev/null +++ b/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp @@ -0,0 +1,180 @@ +// +// ArrayBufferClass.cpp +// +// +// Created by Clement on 7/3/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ArrayBufferClass.h" + +#include + +#include "ArrayBufferPrototype.h" +#include "DataViewClass.h" +#include "ScriptEngineQtScript.h" +#include "TypedArrays.h" + + +static const QString CLASS_NAME = "ArrayBuffer"; + +// FIXME: Q_DECLARE_METATYPE is global and really belongs in a shared header file, not per .cpp like this +// (see DataViewClass.cpp, etc. which would also have to be updated to resolve) +Q_DECLARE_METATYPE(QScriptClass*) +Q_DECLARE_METATYPE(QByteArray*) +int qScriptClassPointerMetaTypeId = qRegisterMetaType(); +int qByteArrayPointerMetaTypeId = qRegisterMetaType(); + +ArrayBufferClass::ArrayBufferClass(ScriptEngineQtScript* scriptEngine) : +QObject(scriptEngine), +QScriptClass(scriptEngine) { + qScriptRegisterMetaType(engine(), toScriptValue, fromScriptValue); + QScriptValue global = engine()->globalObject(); + + // Save string handles for quick lookup + _name = engine()->toStringHandle(CLASS_NAME.toLatin1()); + _byteLength = engine()->toStringHandle(BYTE_LENGTH_PROPERTY_NAME.toLatin1()); + + // build prototype + _proto = engine()->newQObject(new ArrayBufferPrototype(this), + QScriptEngine::QtOwnership, + QScriptEngine::SkipMethodsInEnumeration | + QScriptEngine::ExcludeSuperClassMethods | + QScriptEngine::ExcludeSuperClassProperties); + _proto.setPrototype(global.property("Object").property("prototype")); + + // Register constructor + _ctor = engine()->newFunction(construct, _proto); + _ctor.setData(engine()->toScriptValue(this)); + + engine()->globalObject().setProperty(name(), _ctor); + + // Registering other array types + // The script engine is there parent so it'll delete them with itself + new DataViewClass(scriptEngine); + new Int8ArrayClass(scriptEngine); + new Uint8ArrayClass(scriptEngine); + new Uint8ClampedArrayClass(scriptEngine); + new Int16ArrayClass(scriptEngine); + new Uint16ArrayClass(scriptEngine); + new Int32ArrayClass(scriptEngine); + new Uint32ArrayClass(scriptEngine); + new Float32ArrayClass(scriptEngine); + new Float64ArrayClass(scriptEngine); +} + +QScriptValue ArrayBufferClass::newInstance(qint32 size) { + const qint32 MAX_LENGTH = 100000000; + if (size < 0) { + engine()->evaluate("throw \"ArgumentError: negative length\""); + return QScriptValue(); + } + if (size > MAX_LENGTH) { + engine()->evaluate("throw \"ArgumentError: absurd length\""); + return QScriptValue(); + } + // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) + engine()->reportAdditionalMemoryCost(size); +#endif + QScriptEngine* eng = engine(); + QVariant variant = QVariant::fromValue(QByteArray(size, 0)); + QScriptValue data = eng->newVariant(variant); + return engine()->newObject(this, data); +} + +QScriptValue ArrayBufferClass::newInstance(const QByteArray& ba) { + QScriptValue data = engine()->newVariant(QVariant::fromValue(ba)); + return engine()->newObject(this, data); +} + +QScriptValue ArrayBufferClass::construct(QScriptContext* context, QScriptEngine* engine) { + ArrayBufferClass* cls = qscriptvalue_cast(context->callee().data()); + if (!cls) { + // return if callee (function called) is not of type ArrayBuffer + return QScriptValue(); + } + QScriptValue arg = context->argument(0); + if (!arg.isValid() || !arg.isNumber()) { + return QScriptValue(); + } + + quint32 size = arg.toInt32(); + QScriptValue newObject = cls->newInstance(size); + + if (context->isCalledAsConstructor()) { + // if called with keyword new, replace this object. + context->setThisObject(newObject); + return engine->undefinedValue(); + } + + return newObject; +} + +QScriptClass::QueryFlags ArrayBufferClass::queryProperty(const QScriptValue& object, + const QScriptString& name, + QueryFlags flags, uint* id) { + QByteArray* ba = qscriptvalue_cast(object.data()); + if (ba && name == _byteLength) { + // if the property queried is byteLength, only handle read access + return flags &= HandlesReadAccess; + } + return 0; // No access +} + +QScriptValue ArrayBufferClass::property(const QScriptValue& object, + const QScriptString& name, uint id) { + QByteArray* ba = qscriptvalue_cast(object.data()); + if (ba && name == _byteLength) { + return ba->length(); + } + return QScriptValue(); +} + +QScriptValue::PropertyFlags ArrayBufferClass::propertyFlags(const QScriptValue& object, + const QScriptString& name, uint id) { + return QScriptValue::Undeletable; +} + +QString ArrayBufferClass::name() const { + return _name.toString(); +} + +QScriptValue ArrayBufferClass::prototype() const { + return _proto; +} + +QScriptValue ArrayBufferClass::toScriptValue(QScriptEngine* engine, const QByteArray& ba) { + QScriptValue ctor = engine->globalObject().property(CLASS_NAME); + ArrayBufferClass* cls = qscriptvalue_cast(ctor.data()); + if (!cls) { + if (engine->currentContext()) { + engine->currentContext()->throwError("arrayBufferClass::toScriptValue -- could not get " + CLASS_NAME + " class constructor"); + } + return QScriptValue::NullValue; + } + return cls->newInstance(ba); +} + +void ArrayBufferClass::fromScriptValue(const QScriptValue& object, QByteArray& byteArray) { + if (object.isString()) { + // UTF-8 encoded String + byteArray = object.toString().toUtf8(); + } else if (object.isArray()) { + // Array of uint8s eg: [ 128, 3, 25, 234 ] + auto Uint8Array = object.engine()->globalObject().property("Uint8Array"); + auto typedArray = Uint8Array.construct(QScriptValueList{object}); + if (QByteArray* buffer = qscriptvalue_cast(typedArray.property("buffer"))) { + byteArray = *buffer; + } + } else if (object.isObject()) { + // ArrayBuffer instance (or any JS class that supports coercion into QByteArray*) + if (QByteArray* buffer = qscriptvalue_cast(object.data())) { + byteArray = *buffer; + } + } +} + diff --git a/libraries/script-engine-qtscript/src/ArrayBufferClass.h b/libraries/script-engine/src/qtscript/ArrayBufferClass.h similarity index 100% rename from libraries/script-engine-qtscript/src/ArrayBufferClass.h rename to libraries/script-engine/src/qtscript/ArrayBufferClass.h diff --git a/libraries/script-engine-qtscript/src/ArrayBufferPrototype.cpp b/libraries/script-engine/src/qtscript/ArrayBufferPrototype.cpp similarity index 98% rename from libraries/script-engine-qtscript/src/ArrayBufferPrototype.cpp rename to libraries/script-engine/src/qtscript/ArrayBufferPrototype.cpp index 2523a47e27e..ad5a68ec796 100644 --- a/libraries/script-engine-qtscript/src/ArrayBufferPrototype.cpp +++ b/libraries/script-engine/src/qtscript/ArrayBufferPrototype.cpp @@ -15,8 +15,7 @@ #include #include - -#include "ArrayBufferClass.h" +#include static const int QCOMPRESS_HEADER_POSITION = 0; static const int QCOMPRESS_HEADER_SIZE = 4; diff --git a/libraries/script-engine-qtscript/src/ArrayBufferPrototype.h b/libraries/script-engine/src/qtscript/ArrayBufferPrototype.h similarity index 100% rename from libraries/script-engine-qtscript/src/ArrayBufferPrototype.h rename to libraries/script-engine/src/qtscript/ArrayBufferPrototype.h diff --git a/libraries/script-engine-qtscript/src/ArrayBufferViewClass.cpp b/libraries/script-engine/src/qtscript/ArrayBufferViewClass.cpp similarity index 100% rename from libraries/script-engine-qtscript/src/ArrayBufferViewClass.cpp rename to libraries/script-engine/src/qtscript/ArrayBufferViewClass.cpp diff --git a/libraries/script-engine-qtscript/src/ArrayBufferViewClass.h b/libraries/script-engine/src/qtscript/ArrayBufferViewClass.h similarity index 100% rename from libraries/script-engine-qtscript/src/ArrayBufferViewClass.h rename to libraries/script-engine/src/qtscript/ArrayBufferViewClass.h diff --git a/libraries/script-engine-qtscript/src/DataViewClass.cpp b/libraries/script-engine/src/qtscript/DataViewClass.cpp similarity index 100% rename from libraries/script-engine-qtscript/src/DataViewClass.cpp rename to libraries/script-engine/src/qtscript/DataViewClass.cpp diff --git a/libraries/script-engine-qtscript/src/DataViewClass.h b/libraries/script-engine/src/qtscript/DataViewClass.h similarity index 100% rename from libraries/script-engine-qtscript/src/DataViewClass.h rename to libraries/script-engine/src/qtscript/DataViewClass.h diff --git a/libraries/script-engine-qtscript/src/DataViewPrototype.cpp b/libraries/script-engine/src/qtscript/DataViewPrototype.cpp similarity index 98% rename from libraries/script-engine-qtscript/src/DataViewPrototype.cpp rename to libraries/script-engine/src/qtscript/DataViewPrototype.cpp index ff540f5300a..7770e3bce50 100644 --- a/libraries/script-engine-qtscript/src/DataViewPrototype.cpp +++ b/libraries/script-engine/src/qtscript/DataViewPrototype.cpp @@ -13,12 +13,14 @@ #include #include +#include +#include #include #include -#include "DataViewClass.h" +#include "ArrayBufferViewClass.h" Q_DECLARE_METATYPE(QByteArray*) diff --git a/libraries/script-engine-qtscript/src/DataViewPrototype.h b/libraries/script-engine/src/qtscript/DataViewPrototype.h similarity index 100% rename from libraries/script-engine-qtscript/src/DataViewPrototype.h rename to libraries/script-engine/src/qtscript/DataViewPrototype.h diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp new file mode 100644 index 00000000000..142d2dbb2a8 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp @@ -0,0 +1,73 @@ +// +// ScriptContextQtAgent.cpp +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/22/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptContextQtAgent.h" + +#include + +#include "../Scriptable.h" +#include "ScriptContextQtWrapper.h" +#include "ScriptEngineQtScript.h" + +void ScriptContextQtAgent::contextPop() { + if (_prevAgent) { + _prevAgent->contextPop(); + } + if (_engine->currentContext() == _currContext) { + _currContext.reset(); + if (!_contextActive && !_contextStack.empty()) { + _currContext = _contextStack.back(); + _contextStack.pop_back(); + _contextActive = true; + } + } +} + +void ScriptContextQtAgent::contextPush() { + if (_prevAgent) { + _prevAgent->contextPush(); + } + if (_contextActive && _currContext) { + _contextStack.push_back(_currContext); + _contextActive = false; + } + _currContext.reset(); +} + +void ScriptContextQtAgent::functionEntry(qint64 scriptId) { + if (_prevAgent) { + _prevAgent->functionEntry(scriptId); + } + if (scriptId != -1) { + return; + } + if (!_currContext) { + _currContext = ScriptContextQtPointer(new ScriptContextQtWrapper(_engine, static_cast(_engine)->currentContext())); + } + Scriptable::setContext(_currContext.get()); + _contextActive = true; +} + +void ScriptContextQtAgent::functionExit(qint64 scriptId, const QScriptValue& returnValue) { + if (_prevAgent) { + _prevAgent->functionExit(scriptId, returnValue); + } + if (scriptId != -1) { + return; + } + _contextActive = false; + if (!_contextActive && !_contextStack.empty()) { + _currContext = _contextStack.back(); + _contextStack.pop_back(); + Scriptable::setContext(_currContext.get()); + _contextActive = true; + } +} diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h new file mode 100644 index 00000000000..15e02e99348 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h @@ -0,0 +1,47 @@ +// +// ScriptContextQtAgent.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/22/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptContextQtAgent_h +#define hifi_ScriptContextQtAgent_h + +#include +#include +#include + +#include "ScriptEngineQtScript.h" + +class QScriptContext; +class QScriptEngine; +class QScriptValue; +class ScriptContextQtWrapper; +using ScriptContextQtPointer = QSharedPointer; + +class ScriptContextQtAgent : public QScriptEngineAgent { +public: // construction + inline ScriptContextQtAgent(ScriptEngineQtScript* engine, QScriptEngineAgent* prevAgent) : + QScriptEngineAgent(engine), _engine(engine), _prevAgent(prevAgent) {} + virtual ~ScriptContextQtAgent() {} + +public: // QScriptEngineAgent implementation + virtual void contextPop(); + virtual void contextPush(); + virtual void functionEntry(qint64 scriptId); + virtual void functionExit(qint64 scriptId, const QScriptValue& returnValue); + +private: // storage + bool _contextActive = false; + QList _contextStack; + ScriptContextQtPointer _currContext; + ScriptEngineQtScript* _engine; + QScriptEngineAgent* _prevAgent; +}; + +#endif // hifi_ScriptContextQtAgent_h \ No newline at end of file diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp new file mode 100644 index 00000000000..0e37545840a --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp @@ -0,0 +1,92 @@ +// +// ScriptContextQtWrapper.cpp +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/22/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptContextQtWrapper.h" + +#include + +#include "ScriptEngineQtScript.h" +#include "ScriptValueQtWrapper.h" + +ScriptContextQtWrapper* ScriptContextQtWrapper::unwrap(ScriptContext* val) { + if (!val) { + return nullptr; + } + + return dynamic_cast(val); +} + +int ScriptContextQtWrapper::argumentCount() const { + return _context->argumentCount(); +} + +ScriptValuePointer ScriptContextQtWrapper::argument(int index) const { + QScriptValue result = _context->argument(index); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +QStringList ScriptContextQtWrapper::backtrace() const { + return _context->backtrace(); +} + +ScriptValuePointer ScriptContextQtWrapper::callee() const { + QScriptValue result = _context->callee(); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptEnginePointer ScriptContextQtWrapper::engine() const { + return _engine->sharedFromThis(); +} + +ScriptFunctionContextPointer ScriptContextQtWrapper::functionContext() const { + return ScriptFunctionContextPointer(new ScriptFunctionContextQtWrapper(_context)); +} + +ScriptContextPointer ScriptContextQtWrapper::parentContext() const { + QScriptContext* result = _context->parentContext(); + return ScriptContextPointer(new ScriptContextQtWrapper(_engine, result)); +} + +ScriptValuePointer ScriptContextQtWrapper::thisObject() const { + QScriptValue result = _context->thisObject(); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptValuePointer ScriptContextQtWrapper::throwError(const QString& text) { + QScriptValue result = _context->throwError(text); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptValuePointer ScriptContextQtWrapper::throwValue(const ScriptValuePointer& value) { + ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); + if (!unwrapped) { + return _engine->undefinedValue(); + } + QScriptValue result = _context->throwValue(unwrapped->toQtValue()); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + + +QString ScriptFunctionContextQtWrapper::fileName() const { + return _value.fileName(); +} + +QString ScriptFunctionContextQtWrapper::functionName() const { + return _value.functionName(); +} + +ScriptFunctionContext::FunctionType ScriptFunctionContextQtWrapper::functionType() const { + return static_cast(_value.functionType()); +} + +int ScriptFunctionContextQtWrapper::lineNumber() const { + return _value.lineNumber(); +} diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h new file mode 100644 index 00000000000..993fb69a81f --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h @@ -0,0 +1,63 @@ +// +// ScriptContextQtWrapper.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/22/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptContextQtWrapper_h +#define hifi_ScriptContextQtWrapper_h + +#include +#include +#include + +#include "../ScriptContext.h" + +class QScriptContext; +class ScriptEngineQtScript; +class ScriptValue; +using ScriptValuePointer = QSharedPointer; + +class ScriptContextQtWrapper : public ScriptContext { +public: // construction + inline ScriptContextQtWrapper(ScriptEngineQtScript* engine, QScriptContext* context) : _engine(engine), _context(context) {} + static ScriptContextQtWrapper* unwrap(ScriptContext* val); + inline QScriptContext* toQtValue() const { return _context; } + +public: // ScriptContext implementation + virtual int argumentCount() const; + virtual ScriptValuePointer argument(int index) const; + virtual QStringList backtrace() const; + virtual ScriptValuePointer callee() const; + virtual ScriptEnginePointer engine() const; + virtual ScriptFunctionContextPointer functionContext() const; + virtual ScriptContextPointer parentContext() const; + virtual ScriptValuePointer thisObject() const; + virtual ScriptValuePointer throwError(const QString& text); + virtual ScriptValuePointer throwValue(const ScriptValuePointer& value); + +private: // storage + QScriptContext* _context; + ScriptEngineQtScript* _engine; +}; + +class ScriptFunctionContextQtWrapper : public ScriptFunctionContext { +public: // construction + inline ScriptFunctionContextQtWrapper(QScriptContext* context) : _value(context) {} + +public: // ScriptFunctionContext implementation + virtual QString fileName() const; + virtual QString functionName() const; + virtual FunctionType functionType() const; + virtual int lineNumber() const; + +private: // storage + QScriptContextInfo _value; +}; + +#endif // hifi_ScriptContextQtWrapper_h \ No newline at end of file diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp new file mode 100644 index 00000000000..258a792165f --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -0,0 +1,1037 @@ +// +// ScriptEngineQtScript.cpp +// libraries/script-engine-qtscript/src +// +// Created by Brad Hefta-Gaub on 12/14/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptEngineQtScript.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include "../ScriptEngineLogging.h" +#include "../ScriptProgram.h" +#include "../ScriptValue.h" + +#include "ScriptContextQtWrapper.h" +#include "ScriptProgramQtWrapper.h" +#include "ScriptValueQtWrapper.h" + +static const int MAX_MODULE_ID_LENGTH { 4096 }; +static const int MAX_DEBUG_VALUE_LENGTH { 80 }; + +static const QScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = + QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects; +static const QScriptValue::PropertyFlags READONLY_PROP_FLAGS { QScriptValue::ReadOnly | QScriptValue::Undeletable }; +static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_PROP_FLAGS | QScriptValue::SkipInEnumeration }; + +static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; + +Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) +int qfunctionSignatureMetaID = qRegisterMetaType(); + +int scriptEnginePointerMetaID = qRegisterMetaType(); + +bool ScriptEngineQtScript::IS_THREADSAFE_INVOCATION(const QThread* thread, const QString& method) { + if (QThread::currentThread() == thread) { + return true; + } + qCCritical(scriptengine) << QString("Scripting::%1 @ %2 -- ignoring thread-unsafe call from %3") + .arg(method) + .arg(thread ? thread->objectName() : "(!thread)") + .arg(QThread::currentThread()->objectName()); + qCDebug(scriptengine) << "(please resolve on the calling side by using invokeMethod, executeOnScriptThread, etc.)"; + Q_ASSERT(false); + return false; +} + +// engine-aware JS Error copier and factory +QScriptValue ScriptEngineQtScript::makeError(const QScriptValue& _other, const QString& type) { + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return QScriptEngine::nullValue(); + } + auto other = _other; + if (other.isString()) { + other = QScriptEngine::newObject(); + other.setProperty("message", _other.toString()); + } + auto proto = QScriptEngine::globalObject().property(type); + if (!proto.isFunction()) { + proto = QScriptEngine::globalObject().property(other.prototype().property("constructor").property("name").toString()); + } + if (!proto.isFunction()) { +#ifdef DEBUG_JS_EXCEPTIONS + qCDebug(shared) << "BaseScriptEngine::makeError -- couldn't find constructor for" << type << " -- using Error instead"; +#endif + proto = QScriptEngine::globalObject().property("Error"); + } + if (other.engine() != this) { + // JS Objects are parented to a specific script engine instance + // -- this effectively ~clones it locally by routing through a QVariant and back + other = QScriptEngine::toScriptValue(other.toVariant()); + } + // ~ var err = new Error(other.message) + auto err = proto.construct(QScriptValueList({ other.property("message") })); + + // transfer over any existing properties + QScriptValueIterator it(other); + while (it.hasNext()) { + it.next(); + err.setProperty(it.name(), it.value()); + } + return err; +} + +ScriptValuePointer ScriptEngineQtScript::makeError(const ScriptValuePointer& _other, const QString& type) { + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return nullValue(); + } + ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(_other); + QScriptValue other; + if (_other->isString()) { + other = QScriptEngine::newObject(); + other.setProperty("message", _other->toString()); + } else if (unwrapped) { + other = unwrapped->toQtValue(); + } else { + other = QScriptEngine::newVariant(_other->toVariant()); + } + QScriptValue result = makeError(other, type); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +// check syntax and when there are issues returns an actual "SyntaxError" with the details +ScriptValuePointer ScriptEngineQtScript::lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber) { + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return nullValue(); + } + const auto syntaxCheck = checkSyntax(sourceCode); + if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { + auto err = QScriptEngine::globalObject().property("SyntaxError").construct(QScriptValueList({ syntaxCheck.errorMessage() })); + err.setProperty("fileName", fileName); + err.setProperty("lineNumber", syntaxCheck.errorLineNumber()); + err.setProperty("expressionBeginOffset", syntaxCheck.errorColumnNumber()); + err.setProperty("stack", currentContext()->backtrace().join(ScriptManager::SCRIPT_BACKTRACE_SEP)); + { + const auto error = syntaxCheck.errorMessage(); + const auto line = QString::number(syntaxCheck.errorLineNumber()); + const auto column = QString::number(syntaxCheck.errorColumnNumber()); + // for compatibility with legacy reporting + const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, fileName, line, column); + err.setProperty("formatted", message); + } + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(err))); + } + return undefinedValue(); +} + +// this pulls from the best available information to create a detailed snapshot of the current exception +ScriptValuePointer ScriptEngineQtScript::cloneUncaughtException(const QString& extraDetail) { + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return nullValue(); + } + if (!hasUncaughtException()) { + return nullValue(); + } + auto exception = uncaughtException(); + // ensure the error object is engine-local + auto err = makeError(exception); + + // not sure why Qt does't offer uncaughtExceptionFileName -- but the line number + // on its own is often useless/wrong if arbitrarily married to a filename. + // when the error object already has this info, it seems to be the most reliable + auto fileName = exception->property("fileName")->toString(); + auto lineNumber = exception->property("lineNumber")->toInt32(); + + // the backtrace, on the other hand, seems most reliable taken from uncaughtExceptionBacktrace + auto backtrace = uncaughtExceptionBacktrace(); + if (backtrace.isEmpty()) { + // fallback to the error object + backtrace = exception->property("stack")->toString().split(ScriptManager::SCRIPT_BACKTRACE_SEP); + } + // the ad hoc "detail" property can be used now to embed additional clues + auto detail = exception->property("detail")->toString(); + if (detail.isEmpty()) { + detail = extraDetail; + } else if (!extraDetail.isEmpty()) { + detail += "(" + extraDetail + ")"; + } + if (lineNumber <= 0) { + lineNumber = uncaughtExceptionLineNumber(); + } + if (fileName.isEmpty()) { + // climb the stack frames looking for something useful to display + for (auto c = QScriptEngine::currentContext(); c && fileName.isEmpty(); c = c->parentContext()) { + QScriptContextInfo info{ c }; + if (!info.fileName().isEmpty()) { + // take fileName:lineNumber as a pair + fileName = info.fileName(); + lineNumber = info.lineNumber(); + if (backtrace.isEmpty()) { + backtrace = c->backtrace(); + } + break; + } + } + } + err->setProperty("fileName", fileName); + err->setProperty("lineNumber", lineNumber); + err->setProperty("detail", detail); + err->setProperty("stack", backtrace.join(ScriptManager::SCRIPT_BACKTRACE_SEP)); + +#ifdef DEBUG_JS_EXCEPTIONS + err->setProperty("_fileName", exception.property("fileName").toString()); + err->setProperty("_stack", uncaughtExceptionBacktrace().join(SCRIPT_BACKTRACE_SEP)); + err->setProperty("_lineNumber", uncaughtExceptionLineNumber()); +#endif + return err; +} + +bool ScriptEngineQtScript::raiseException(const QScriptValue& exception) { + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return false; + } + if (QScriptEngine::currentContext()) { + // we have an active context / JS stack frame so throw the exception per usual + QScriptEngine::currentContext()->throwValue(makeError(exception)); + return true; + } else if(_manager) { + // we are within a pure C++ stack frame (ie: being called directly by other C++ code) + // in this case no context information is available so just emit the exception for reporting + QScriptValue thrown = makeError(exception); + emit _manager->unhandledException(ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(thrown)))); + } + return false; +} + +bool ScriptEngineQtScript::maybeEmitUncaughtException(const QString& debugHint) { + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return false; + } + if (!isEvaluating() && hasUncaughtException() && _manager) { + emit _manager->unhandledException(cloneUncaughtException(debugHint)); + clearExceptions(); + return true; + } + return false; +} + +// Lambda +QScriptValue ScriptEngineQtScript::newLambdaFunction(std::function operation, + const QScriptValue& data, + const QScriptEngine::ValueOwnership& ownership) { + auto lambda = new Lambda(this, operation, data); + auto object = QScriptEngine::newQObject(lambda, ownership); + auto call = object.property("call"); + call.setPrototype(object); // context->callee().prototype() === Lambda QObject + call.setData(data); // context->callee().data() will === data param + return call; +} +QString Lambda::toString() const { + return QString("[Lambda%1]").arg(data.isValid() ? " " + data.toString() : data.toString()); +} + +Lambda::~Lambda() { +#ifdef DEBUG_JS_LAMBDA_FUNCS + qDebug() << "~Lambda" + << "this" << this; +#endif +} + +Lambda::Lambda(ScriptEngineQtScript* engine, + std::function operation, + QScriptValue data) : + engine(engine), + operation(operation), data(data) { +#ifdef DEBUG_JS_LAMBDA_FUNCS + qDebug() << "Lambda" << data.toString(); +#endif +} +QScriptValue Lambda::call() { + if (!engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { + return static_cast(engine)->nullValue(); + } + return operation(static_cast(engine)->currentContext(), engine); +} + +#ifdef DEBUG_JS +void ScriptEngineQtScript::_debugDump(const QString& header, const QScriptValue& object, const QString& footer) { + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return; + } + if (!header.isEmpty()) { + qCDebug(shared) << header; + } + if (!object.isObject()) { + qCDebug(shared) << "(!isObject)" << object.toVariant().toString() << object.toString(); + return; + } + QScriptValueIterator it(object); + while (it.hasNext()) { + it.next(); + qCDebug(shared) << it.name() << ":" << it.value().toString(); + } + if (!footer.isEmpty()) { + qCDebug(shared) << footer; + } +} +#endif + +static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { + // assemble the message by concatenating our arguments + QString message = ""; + for (int i = 0; i < context->argumentCount(); i++) { + if (i > 0) { + message += " "; + } + message += context->argument(i).toString(); + } + + // was this generated by a script engine? If we don't recognize it then send the message and exit + ScriptEngineQtScript* scriptEngine = qobject_cast(engine); + if (!scriptEngine) { + qCDebug(scriptengine_script, "%s", qUtf8Printable(message)); + return QScriptValue(); + } + + QString filename; + auto scriptManager = scriptEngine->manager(); + if (scriptManager) { + filename = scriptManager->getFilename(); + } + + // This message was sent by one of our script engines, let's try to see if we can find the source. + // Note that the first entry in the backtrace should be "print" and is somewhat useless to us + AbstractLoggerInterface* loggerInterface = AbstractLoggerInterface::get(); + if (loggerInterface && loggerInterface->showSourceDebugging()) { + QScriptContext* userContext = context; + while (userContext && QScriptContextInfo(userContext).functionType() == QScriptContextInfo::NativeFunction) { + userContext = userContext->parentContext(); + } + QString location; + if (userContext) { + QScriptContextInfo contextInfo(userContext); + QString fileName = contextInfo.fileName(); + int lineNumber = contextInfo.lineNumber(); + QString functionName = contextInfo.functionName(); + + location = functionName; + if (!fileName.isEmpty()) { + if (location.isEmpty()) { + location = fileName; + } else { + location = QString("%1 at %2").arg(location).arg(fileName); + } + } + if (lineNumber != -1) { + location = QString("%1:%2").arg(location).arg(lineNumber); + } + } + if (location.isEmpty()) { + location = filename; + } + + // give the script engine a chance to notify the system about this message + scriptEngine->print(message); + + // send the message to debug log + qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(location), qUtf8Printable(message)); + } else { + scriptEngine->print(message); + // prefix the script engine name to help disambiguate messages in the main debug log + qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(filename), qUtf8Printable(message)); + } + + return QScriptValue(); +} + +ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : + QScriptEngine(), + _manager(scriptManager), + _arrayBufferClass(new ArrayBufferClass(this)) +{ + if (_manager) { + connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { + if (hasUncaughtException()) { + // the engine's uncaughtException() seems to produce much better stack traces here + emit _manager->unhandledException(cloneUncaughtException("signalHandlerException")); + clearExceptions(); + } else { + // ... but may not always be available -- so if needed we fallback to the passed exception + QScriptValue thrown = makeError(exception); + emit _manager->unhandledException(ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(thrown)))); + } + }, Qt::DirectConnection); + } + + QScriptValue null = QScriptEngine::nullValue(); + _nullValue = ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(null))); + + QScriptValue undefined = QScriptEngine::undefinedValue(); + _undefinedValue = ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(undefined))); + + QScriptEngine::setProcessEventsInterval(MSECS_PER_SECOND); +} + +bool ScriptEngineQtScript::isDebugMode() const { +#if defined(DEBUG) + return true; +#else + return false; +#endif +} + +ScriptEngineQtScript::~ScriptEngineQtScript() {} + +void ScriptEngineQtScript::disconnectNonEssentialSignals() { + disconnect(); + QThread* workerThread; + // Ensure the thread should be running, and does exist + if (_isRunning && _isThreaded && (workerThread = QScriptEngine::thread())) { + connect(this, &QObject::destroyed, workerThread, &QThread::quit); + connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); + } +} + +void ScriptEngineQtScript::executeOnScriptThread(std::function function, const Qt::ConnectionType& type ) { + if (QThread::currentThread() != QScriptEngine::thread()) { + QMetaObject::invokeMethod(this, "executeOnScriptThread", type, Q_ARG(std::function, function)); + return; + } + + function(); +} + +void ScriptEngineQtScript::registerEnum(const QString& enumName, QMetaEnum newEnum) { + if (!newEnum.isValid()) { + qCCritical(scriptengine) << "registerEnum called on invalid enum with name " << enumName; + return; + } + + for (int i = 0; i < newEnum.keyCount(); i++) { + const char* keyName = newEnum.key(i); + QString fullName = enumName + "." + keyName; + registerValue(fullName, newEnum.keyToValue(keyName)); + } +} + +void ScriptEngineQtScript::registerValue(const QString& valueName, QScriptValue value) { + if (QThread::currentThread() != QScriptEngine::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; +#endif + QMetaObject::invokeMethod(this, "registerValue", + Q_ARG(const QString&, valueName), + Q_ARG(QScriptValue, value)); + return; + } + + QStringList pathToValue = valueName.split("."); + int partsToGo = pathToValue.length(); + QScriptValue partObject = globalObject(); + + for (const auto& pathPart : pathToValue) { + partsToGo--; + if (!partObject.property(pathPart).isValid()) { + if (partsToGo > 0) { + //QObject *object = new QObject; + QScriptValue partValue = newArray(); //newQObject(object, QScriptEngine::ScriptOwnership); + partObject.setProperty(pathPart, partValue); + } else { + partObject.setProperty(pathPart, value); + } + } + partObject = partObject.property(pathPart); + } +} + +void ScriptEngineQtScript::registerGlobalObject(const QString& name, QObject* object) { + if (QThread::currentThread() != QScriptEngine::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; +#endif + QMetaObject::invokeMethod(this, "registerGlobalObject", + Q_ARG(const QString&, name), + Q_ARG(QObject*, object)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; +#endif + + if (!QScriptEngine::globalObject().property(name).isValid()) { + if (object) { + QScriptValue value = QScriptEngine::newQObject(object, QScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); + QScriptEngine::globalObject().setProperty(name, value); + } else { + QScriptEngine::globalObject().setProperty(name, QScriptValue()); + } + } +} + +void ScriptEngineQtScript::registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != QScriptEngine::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; +#endif + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; +#endif + + QScriptValue scriptFun = QScriptEngine::newFunction(functionSignature, numArguments); + QScriptEngine::globalObject().setProperty(name, scriptFun); +} + +void ScriptEngineQtScript::registerFunction(const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != QScriptEngine::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; +#endif + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(ScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; +#endif + + auto scriptFun = newFunction(functionSignature, numArguments); + globalObject()->setProperty(name, scriptFun); +} + +void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != QScriptEngine::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; +#endif + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; +#endif + + QScriptValue object = QScriptEngine::globalObject().property(parent); + if (object.isValid()) { + QScriptValue scriptFun = QScriptEngine::newFunction(functionSignature, numArguments); + object.setProperty(name, scriptFun); + } +} + +void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != QScriptEngine::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; +#endif + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(ScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; +#endif + + auto object = globalObject()->property(parent); + if (object->isValid()) { + auto scriptFun = newFunction(functionSignature, numArguments); + object->setProperty(name, scriptFun); + } +} + +void ScriptEngineQtScript::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, + QScriptEngine::FunctionSignature setter, const QString& parent) { + if (QThread::currentThread() != QScriptEngine::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + " name:" << name << "parent:" << parent; +#endif + QMetaObject::invokeMethod(this, "registerGetterSetter", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, getter), + Q_ARG(QScriptEngine::FunctionSignature, setter), + Q_ARG(const QString&, parent)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; +#endif + + QScriptValue setterFunction = QScriptEngine::newFunction(setter, 1); + QScriptValue getterFunction = QScriptEngine::newFunction(getter); + + if (!parent.isNull() && !parent.isEmpty()) { + QScriptValue object = QScriptEngine::globalObject().property(parent); + if (object.isValid()) { + object.setProperty(name, setterFunction, QScriptValue::PropertySetter); + object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); + } + } else { + QScriptEngine::globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); + QScriptEngine::globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); + } +} + +void ScriptEngineQtScript::registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, + ScriptEngine::FunctionSignature setter, const QString& parent) { + if (QThread::currentThread() != QScriptEngine::thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + " name:" << name << "parent:" << parent; +#endif + QMetaObject::invokeMethod(this, "registerGetterSetter", + Q_ARG(const QString&, name), + Q_ARG(ScriptEngine::FunctionSignature, getter), + Q_ARG(ScriptEngine::FunctionSignature, setter), + Q_ARG(const QString&, parent)); + return; + } +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "ScriptEngineQtScript::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; +#endif + + auto setterFunction = newFunction(setter, 1); + auto getterFunction = newFunction(getter); + + if (!parent.isNull() && !parent.isEmpty()) { + auto object = globalObject()->property(parent); + if (object->isValid()) { + object->setProperty(name, setterFunction, ScriptValue::PropertySetter); + object->setProperty(name, getterFunction, ScriptValue::PropertyGetter); + } + } else { + globalObject()->setProperty(name, setterFunction, ScriptValue::PropertySetter); + globalObject()->setProperty(name, getterFunction, ScriptValue::PropertyGetter); + } +} + +ScriptValuePointer ScriptEngineQtScript::evaluateInClosure(const ScriptValuePointer& _closure, + const ScriptProgramPointer& _program) { + PROFILE_RANGE(script, "evaluateInClosure"); + if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { + return nullValue(); + } + ScriptProgramQtWrapper* unwrappedProgram = ScriptProgramQtWrapper::unwrap(_program); + if (unwrappedProgram == nullptr) { + return nullValue(); + } + const QScriptProgram& program = unwrappedProgram->toQtValue(); + + const auto fileName = program.fileName(); + const auto shortName = QUrl(fileName).fileName(); + + ScriptValueQtWrapper* unwrappedClosure = ScriptValueQtWrapper::unwrap(_closure); + if (unwrappedClosure == nullptr) { + return nullValue(); + } + const QScriptValue& closure = unwrappedClosure->toQtValue(); + + QScriptValue oldGlobal; + auto global = closure.property("global"); + if (global.isObject()) { +#ifdef DEBUG_JS + qCDebug(shared) << " setting global = closure.global" << shortName; +#endif + oldGlobal = QScriptEngine::globalObject(); + setGlobalObject(global); + } + + auto context = pushContext(); + + auto thiz = closure.property("this"); + if (thiz.isObject()) { +#ifdef DEBUG_JS + qCDebug(shared) << " setting this = closure.this" << shortName; +#endif + context->setThisObject(thiz); + } + + context->pushScope(closure); +#ifdef DEBUG_JS + qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName); +#endif + ScriptValuePointer result; + { + auto qResult = QScriptEngine::evaluate(program); + + if (hasUncaughtException()) { + auto err = cloneUncaughtException(__FUNCTION__); +#ifdef DEBUG_JS_EXCEPTIONS + qCWarning(shared) << __FUNCTION__ << "---------- hasCaught:" << err.toString() << result.toString(); + err.setProperty("_result", result); +#endif + result = err; + } else { + result = ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(qResult))); + } + } +#ifdef DEBUG_JS + qCDebug(shared) << QString("[%1] //evaluateInClosure %2").arg(isEvaluating()).arg(shortName); +#endif + popContext(); + + if (oldGlobal.isValid()) { +#ifdef DEBUG_JS + qCDebug(shared) << " restoring global" << shortName; +#endif + setGlobalObject(oldGlobal); + } + + return result; +} + +ScriptValuePointer ScriptEngineQtScript::evaluate(const QString& sourceCode, const QString& fileName) { + if (_manager && _manager->isStopped()) { + return undefinedValue(); // bail early + } + + if (QThread::currentThread() != QScriptEngine::thread()) { + ScriptValuePointer result; +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + "sourceCode:" << sourceCode << " fileName:" << fileName; +#endif + BLOCKING_INVOKE_METHOD(this, "evaluate", + Q_RETURN_ARG(ScriptValuePointer, result), + Q_ARG(const QString&, sourceCode), + Q_ARG(const QString&, fileName)); + return result; + } + + // Check syntax + auto syntaxError = lintScript(sourceCode, fileName); + if (syntaxError->isError()) { + if (!isEvaluating()) { + syntaxError->setProperty("detail", "evaluate"); + } + raiseException(syntaxError); + maybeEmitUncaughtException("lint"); + return syntaxError; + } + QScriptProgram program { sourceCode, fileName, 1 }; + if (program.isNull()) { + // can this happen? + auto err = makeError(newValue("could not create QScriptProgram for " + fileName)); + raiseException(err); + maybeEmitUncaughtException("compile"); + return err; + } + + QScriptValue result = QScriptEngine::evaluate(program); + maybeEmitUncaughtException("evaluate"); + + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +Q_INVOKABLE ScriptValuePointer ScriptEngineQtScript::evaluate(const ScriptProgramPointer& program) { + if (_manager && _manager->isStopped()) { + return undefinedValue(); // bail early + } + + if (QThread::currentThread() != QScriptEngine::thread()) { + ScriptValuePointer result; +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + "sourceCode:" << sourceCode << " fileName:" << fileName; +#endif + BLOCKING_INVOKE_METHOD(this, "evaluate", + Q_RETURN_ARG(ScriptValuePointer, result), + Q_ARG(const ScriptProgramPointer&, program)); + return result; + } + + ScriptProgramQtWrapper* unwrapped = ScriptProgramQtWrapper::unwrap(program); + if (!unwrapped) { + auto err = makeError(newValue("could not unwrap program")); + raiseException(err); + maybeEmitUncaughtException("compile"); + return err; + } + + const QScriptProgram& qProgram = unwrapped->toQtValue(); + if (qProgram.isNull()) { + // can this happen? + auto err = makeError(newValue("requested program is empty")); + raiseException(err); + maybeEmitUncaughtException("compile"); + return err; + } + + QScriptValue result = QScriptEngine::evaluate(qProgram); + maybeEmitUncaughtException("evaluate"); + + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + + +void ScriptEngineQtScript::updateMemoryCost(const qint64& deltaSize) { + if (deltaSize > 0) { + // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only. +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) + reportAdditionalMemoryCost(deltaSize); +#endif + } +} + +void ScriptEngineQtScript::print(const QString& message) { + QString filename; + auto scriptManager = manager(); + if (scriptManager) { + filename = scriptManager->getFilename(); + } + + emit printedMessage(message, filename); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ScriptEngine implementation + +ScriptValuePointer ScriptEngineQtScript::globalObject() const { + QScriptValue global = QScriptEngine::globalObject(); // can't cache the value as it may change + return ScriptValuePointer(new ScriptValueQtWrapper(const_cast < ScriptEngineQtScript*>(this), std::move(global))); +} + +ScriptManager* ScriptEngineQtScript::manager() const { + return _manager; +} + +ScriptValuePointer ScriptEngineQtScript::newArray(uint length) { + QScriptValue result = QScriptEngine::newArray(length); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newArrayBuffer(const QByteArray& message) { + QScriptValue data = QScriptEngine::newVariant(QVariant::fromValue(message)); + QScriptValue ctor = QScriptEngine::globalObject().property("ArrayBuffer"); + auto array = qscriptvalue_cast(ctor.data()); + if (!array) { + return undefinedValue(); + } + QScriptValue result = QScriptEngine::newObject(array, data); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newObject() { + QScriptValue result = QScriptEngine::newObject(); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, const QString& fileName) { + QScriptProgram result(sourceCode, fileName); + return ScriptProgramPointer(new ScriptProgramQtWrapper(this, result)); +} + +ScriptValuePointer ScriptEngineQtScript::newQObject(QObject* obj, + ScriptEngine::ValueOwnership ownership, + const ScriptEngine::QObjectWrapOptions& options) { + QScriptValue result = QScriptEngine::newQObject(obj, static_cast(ownership), + (QScriptEngine::QObjectWrapOptions)(int)options); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newValue(bool value) { + QScriptValue result(this, value); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newValue(int value) { + QScriptValue result(this, value); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newValue(uint value) { + QScriptValue result(this, value); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newValue(double value) { + QScriptValue result(this, value); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newValue(const QString& value) { + QScriptValue result(this, value); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newValue(const QLatin1String& value) { + QScriptValue result(this, value); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newValue(const char* value) { + QScriptValue result(this, value); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::newVariant(const QVariant& value) { + QScriptValue result = QScriptEngine::newVariant(value); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +ScriptValuePointer ScriptEngineQtScript::nullValue() { + return _nullValue; +} + +void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype){ + ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype); + if (unwrappedPrototype) { + QScriptEngine::setDefaultPrototype(metaTypeId, unwrappedPrototype->toQtValue()); + } +} + +ScriptValuePointer ScriptEngineQtScript::undefinedValue() { + return _undefinedValue; +} + +void ScriptEngineQtScript::abortEvaluation() { + QScriptEngine::abortEvaluation(); +} + +void ScriptEngineQtScript::clearExceptions() { + QScriptEngine::clearExceptions(); +} + +ScriptContext* ScriptEngineQtScript::currentContext() const { + QScriptContext* localCtx = QScriptEngine::currentContext(); + if (!localCtx) { + return nullptr; + } + if (!_currContext || _currContext->toQtValue() != localCtx) { + _currContext = ScriptContextQtPointer(new ScriptContextQtWrapper(const_cast(this), localCtx)); + } + return _currContext.get(); +} + +bool ScriptEngineQtScript::hasUncaughtException() const { + return QScriptEngine::hasUncaughtException(); +} + +bool ScriptEngineQtScript::isEvaluating() const { + return QScriptEngine::isEvaluating(); +} + +ScriptValuePointer ScriptEngineQtScript::newFunction(ScriptEngine::FunctionSignature fun, int length) { + auto innerFunc = [](QScriptContext* _context, QScriptEngine* _engine) -> QScriptValue { + auto callee = _context->callee(); + QVariant funAddr = callee.property("_func").toVariant(); + ScriptEngine::FunctionSignature fun = reinterpret_cast(funAddr.toULongLong()); + ScriptEngineQtScript* engine = static_cast(_engine); + ScriptContextQtWrapper context(engine, _context); + ScriptValuePointer result = fun(&context, engine); + ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(result); + return unwrapped ? unwrapped->toQtValue() : QScriptValue(); + }; + + QScriptValue result = QScriptEngine::newFunction(innerFunc, length); + auto funAddr = QScriptEngine::newVariant(QVariant(reinterpret_cast(fun))); + result.setProperty("_func", funAddr, QScriptValue::PropertyFlags(QScriptValue::ReadOnly + QScriptValue::Undeletable + QScriptValue::SkipInEnumeration)); + return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); +} + +void ScriptEngineQtScript::setObjectName(const QString& name) { + QScriptEngine::setObjectName(name); +} + +bool ScriptEngineQtScript::setProperty(const char* name, const QVariant& value) { + return QScriptEngine::setProperty(name, value); +} + +void ScriptEngineQtScript::setProcessEventsInterval(int interval) { + QScriptEngine::setProcessEventsInterval(interval); +} + +QThread* ScriptEngineQtScript::thread() const { + return QScriptEngine::thread(); +} + +ScriptValuePointer ScriptEngineQtScript::uncaughtException() const { + QScriptValue result = QScriptEngine::uncaughtException(); + return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); +} + +QStringList ScriptEngineQtScript::uncaughtExceptionBacktrace() const { + return QScriptEngine::uncaughtExceptionBacktrace(); +} + +int ScriptEngineQtScript::uncaughtExceptionLineNumber() const { + return QScriptEngine::uncaughtExceptionLineNumber(); +} + +bool ScriptEngineQtScript::raiseException(const ScriptValuePointer& exception) { + ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(exception); + QScriptValue qException = unwrapped ? unwrapped->toQtValue() : QScriptEngine::newVariant(exception->toVariant()); + return raiseException(qException); +} + +ScriptValuePointer ScriptEngineQtScript::create(int type, const void* ptr) { + QScriptValue result = qScriptValueFromValue_helper(this, type, ptr); + return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); +} + +bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, void* ptr) { + ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); + if (unwrapped == nullptr) { + return false; + } + return qscriptvalue_cast_helper(unwrapped->toQtValue(), type, ptr); +} +/* +void ScriptEngineQtScript::registerCustomType(int type, + ScriptEngine::MarshalFunction mf, + ScriptEngine::DemarshalFunction df, + const ScriptValuePointer& prototype) { + ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(prototype); + if (unwrapped != nullptr) { + qScriptRegisterMetaType_helper(this, type, mf, df, unwrapped->toQtValue()); + } +} +*/ diff --git a/libraries/script-engine-qtscript/src/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h similarity index 66% rename from libraries/script-engine-qtscript/src/ScriptEngineQtScript.h rename to libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index f42da037792..bb7a3a4017e 100644 --- a/libraries/script-engine-qtscript/src/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -13,50 +13,27 @@ #ifndef hifi_ScriptEngineQtScript_h #define hifi_ScriptEngineQtScript_h -//#include -//#include - -//#include -//#include -//#include -//#include -//#include - #include +#include #include #include #include +#include +#include + #include #include -#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -#include -#include - -//#include "PointerEvent.h" +#include "../ScriptEngine.h" +#include "../ScriptManager.h" + #include "ArrayBufferClass.h" -//#include "AssetScriptingInterface.h" -//#include "AudioScriptingInterface.h" -#include "BaseScriptEngine.h" -//#include "ExternalResource.h" -//#include "Quat.h" -//#include "Mat4.h" -//#include "ScriptCache.h" -//#include "ScriptUUID.h" -//#include "Vec3.h" -//#include "ConsoleScriptingInterface.h" -//#include "SettingHandle.h" -//#include "Profile.h" - -//class QScriptEngineDebugger; + +class ScriptContextQtWrapper; +class ScriptEngineQtScript; class ScriptManager; +using ScriptEngineQtScriptPointer = QSharedPointer; +using ScriptContextQtPointer = QSharedPointer; Q_DECLARE_METATYPE(ScriptEngineQtScriptPointer) @@ -92,18 +69,34 @@ Q_DECLARE_METATYPE(ScriptEngineQtScriptPointer) * Read-only. * @property {Script.ResourceBuckets} ExternalPaths - External resource buckets. */ -class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { +class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public QEnableSharedFromThis { Q_OBJECT - using Base = BaseScriptEngine; public: // ScriptEngine implementation + virtual void abortEvaluation(); + virtual void clearExceptions(); + virtual ScriptValuePointer cloneUncaughtException(const QString& detail = QString()); + virtual ScriptContext* currentContext() const; + //virtual ScriptValuePointer evaluate(const QString& program, const QString& fileName = QString()); + //virtual ScriptValuePointer evaluate(const ScriptProgramPointer &program); + //virtual ScriptValuePointer evaluateInClosure(const ScriptValuePointer& locals, const ScriptProgramPointer& program); virtual ScriptValuePointer globalObject() const; + virtual bool hasUncaughtException() const; + virtual bool isEvaluating() const; + virtual ScriptValuePointer lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1); + virtual ScriptValuePointer makeError(const ScriptValuePointer& other, const QString& type = "Error"); virtual ScriptManager* manager() const; + + // if there is a pending exception and we are at the top level (non-recursive) stack frame, this emits and resets it + virtual bool maybeEmitUncaughtException(const QString& debugHint = QString()); + virtual ScriptValuePointer newArray(uint length = 0); virtual ScriptValuePointer newArrayBuffer(const QByteArray& message); + virtual ScriptValuePointer newFunction(ScriptEngine::FunctionSignature fun, int length = 0); virtual ScriptValuePointer newObject(); virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName); - virtual ScriptValuePointer newQObject(QObject* obj); + virtual ScriptValuePointer newQObject(QObject *object, ScriptEngine::ValueOwnership ownership = ScriptEngine::QtOwnership, + const ScriptEngine::QObjectWrapOptions &options = ScriptEngine::QObjectWrapOptions()); virtual ScriptValuePointer newValue(bool value); virtual ScriptValuePointer newValue(int value); virtual ScriptValuePointer newValue(uint value); @@ -113,8 +106,41 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { virtual ScriptValuePointer newValue(const char* value); virtual ScriptValuePointer newVariant(const QVariant& value); virtual ScriptValuePointer nullValue(); + virtual bool raiseException(const ScriptValuePointer& exception); + //virtual void registerEnum(const QString& enumName, QMetaEnum newEnum); + //Q_INVOKABLE virtual void registerFunction(const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); + //Q_INVOKABLE virtual void registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); + //Q_INVOKABLE virtual void registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent = QString("")); + //virtual void registerGlobalObject(const QString& name, QObject* object); virtual void setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype); + virtual void setObjectName(const QString& name); + virtual bool setProperty(const char* name, const QVariant& value); + virtual void setProcessEventsInterval(int interval); + virtual QThread* thread() const; virtual ScriptValuePointer undefinedValue(); + virtual ScriptValuePointer uncaughtException() const; + virtual QStringList uncaughtExceptionBacktrace() const; + virtual int uncaughtExceptionLineNumber() const; + + // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways + inline bool IS_THREADSAFE_INVOCATION(const QString& method) { return ScriptEngine::IS_THREADSAFE_INVOCATION(method); } + +protected: // brought over from BaseScriptEngine + /*@jsdoc + * @function Script.makeError + * @param {object} [other] - Other. + * @param {string} [type="Error"] - Error. + * @returns {object} Object. + * @deprecated This function is deprecated and will be removed. + */ + Q_INVOKABLE QScriptValue makeError(const QScriptValue& other = QScriptValue(), const QString& type = "Error"); + + // if the currentContext() is valid then throw the passed exception; otherwise, immediately emit it. + // note: this is used in cases where C++ code might call into JS API methods directly + bool raiseException(const QScriptValue& exception); + + // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways + static bool IS_THREADSAFE_INVOCATION(const QThread* thread, const QString& method); public: ScriptEngineQtScript(ScriptManager* scriptManager = nullptr); @@ -131,7 +157,7 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { * @deprecated This function is deprecated and will be removed. */ /// registers a global object by name - Q_INVOKABLE void registerGlobalObject(const QString& name, QObject* object); + Q_INVOKABLE virtual void registerGlobalObject(const QString& name, QObject* object); /*@jsdoc * @function Script.registerGetterSetter @@ -145,6 +171,8 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { Q_INVOKABLE void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, const QString& parent = QString("")); + Q_INVOKABLE virtual void registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent = QString("")); + /*@jsdoc * @function Script.registerFunction * @param {string} name - Name. @@ -155,6 +183,9 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { /// register a global function Q_INVOKABLE void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); + + Q_INVOKABLE virtual void registerFunction(const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); + /*@jsdoc * @function Script.registerFunction * @param {string} parent - Parent. @@ -167,6 +198,9 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { Q_INVOKABLE void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); + + Q_INVOKABLE virtual void registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); + /*@jsdoc * @function Script.registerEnum * @param {string} name - Name. @@ -176,7 +210,7 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { // WARNING: This function must be called after a registerGlobalObject that creates the namespace this enum is located in, or // the globalObject won't function. E.g., if you have a Foo object and a Foo.FooType enum, Foo must be registered first. /// registers a global enum - Q_INVOKABLE void registerEnum(const QString& enumName, QMetaEnum newEnum); + Q_INVOKABLE virtual void registerEnum(const QString& enumName, QMetaEnum newEnum); /*@jsdoc * @function Script.registerValue @@ -196,7 +230,10 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { * @deprecated This function is deprecated and will be removed. */ /// evaluate some code in the context of the ScriptEngineQtScript and return the result - Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName, int lineNumber = 1); // this is also used by the script tool widget + Q_INVOKABLE virtual ScriptValuePointer evaluate(const QString& program, const QString& fileName); // this is also used by the script tool widget + + + Q_INVOKABLE virtual ScriptValuePointer evaluate(const ScriptProgramPointer& program); /*@jsdoc * @function Script.evaluateInClosure @@ -205,7 +242,7 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { * @returns {object} Object. * @deprecated This function is deprecated and will be removed. */ - Q_INVOKABLE QScriptValue evaluateInClosure(const QScriptValue& locals, const QScriptProgram& program); + Q_INVOKABLE virtual ScriptValuePointer evaluateInClosure(const ScriptValuePointer& locals, const ScriptProgramPointer& program); /*@jsdoc * Checks whether the application was compiled as a debug build. @@ -245,14 +282,12 @@ class ScriptEngineQtScript : public BaseScriptEngine, public ScriptEngine { // NOTE - this is used by the TypedArray implementation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } -public slots: - /*@jsdoc * @function Script.updateMemoryCost * @param {number} deltaSize - Delta size. * @deprecated This function is deprecated and will be removed. */ - void updateMemoryCost(const qint64&); + virtual void updateMemoryCost(const qint64& deltaSize); signals: @@ -372,6 +407,20 @@ public slots: // script is updated (goes from RUNNING to ERROR_RUNNING_SCRIPT, for example) void entityScriptDetailsUpdated(); +public: // not for public use, but I don't like how Qt strings this along with private friend functions + virtual ScriptValuePointer create(int type, const void* ptr); + virtual bool convert(const ScriptValuePointer& value, int type, void* ptr); + virtual void registerCustomType(int type, ScriptEngine::MarshalFunction mf, ScriptEngine::DemarshalFunction df, const ScriptValuePointer& prototype); + +protected: + // like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues + // even though the context/engine parameters are redundant in most cases, the function signature matches `newFunction` + // anyway so that newLambdaFunction can be used to rapidly prototype / test utility APIs and then if becoming + // permanent more easily promoted into regular static newFunction scenarios. + QScriptValue newLambdaFunction(std::function operation, + const QScriptValue& data = QScriptValue(), + const QScriptEngine::ValueOwnership& ownership = QScriptEngine::AutoOwnership); + protected: /*@jsdoc @@ -384,6 +433,10 @@ public slots: QPointer _manager; + ScriptValuePointer _nullValue; + ScriptValuePointer _undefinedValue; + mutable ScriptContextQtPointer _currContext; + std::atomic _isRunning { false }; bool _isThreaded { false }; @@ -394,4 +447,23 @@ public slots: ArrayBufferClass* _arrayBufferClass; }; -#endif // hifi_ScriptEngineQtScript_h +// Lambda helps create callable QScriptValues out of std::functions: +// (just meant for use from within the script engine itself) +class Lambda : public QObject { + Q_OBJECT +public: + Lambda(ScriptEngineQtScript* engine, + std::function operation, + QScriptValue data); + ~Lambda(); +public slots: + QScriptValue call(); + QString toString() const; + +private: + ScriptEngineQtScript* engine; + std::function operation; + QScriptValue data; +}; + +#endif // hifi_ScriptEngineQtScript_h diff --git a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp new file mode 100644 index 00000000000..be5f4df111a --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp @@ -0,0 +1,55 @@ +// +// ScriptProgramQtWrapper.cpp +// libraries/script-engine/src +// +// Created by Heather Anderson on 8/24/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptProgramQtWrapper.h" + +#include + +#include "ScriptEngineQtScript.h" +#include "ScriptValueQtWrapper.h" + +ScriptProgramQtWrapper* ScriptProgramQtWrapper::unwrap(ScriptProgramPointer val) { + if (!val) { + return nullptr; + } + + return dynamic_cast(val.get()); +} + +ScriptSyntaxCheckResultPointer ScriptProgramQtWrapper::checkSyntax() const { + QScriptSyntaxCheckResult result = _engine->checkSyntax(_value.sourceCode()); + return ScriptSyntaxCheckResultPointer(new ScriptSyntaxCheckResultQtWrapper(std::move(result))); +} + +QString ScriptProgramQtWrapper::fileName() const { + return _value.fileName(); +} + +QString ScriptProgramQtWrapper::sourceCode() const { + return _value.sourceCode(); +} + + +int ScriptSyntaxCheckResultQtWrapper::errorColumnNumber() const { + return _value.errorColumnNumber(); +} + +int ScriptSyntaxCheckResultQtWrapper::errorLineNumber() const { + return _value.errorLineNumber(); +} + +QString ScriptSyntaxCheckResultQtWrapper::errorMessage() const { + return _value.errorMessage(); +} + +ScriptSyntaxCheckResult::State ScriptSyntaxCheckResultQtWrapper::state() const { + return static_cast(_value.state()); +} diff --git a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h new file mode 100644 index 00000000000..b09c58b0d94 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h @@ -0,0 +1,55 @@ +// +// ScriptProgramQtWrapper.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/21/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptProgramQtWrapper_h +#define hifi_ScriptProgramQtWrapper_h + +#include +#include + +#include "../ScriptProgram.h" +#include "ScriptEngineQtScript.h" + +class ScriptProgramQtWrapper : public ScriptProgram { +public: // construction + inline ScriptProgramQtWrapper(ScriptEngineQtScript* engine, const QScriptProgram& value) : + _engine(engine), _value(value) {} + inline ScriptProgramQtWrapper(ScriptEngineQtScript* engine, QScriptProgram&& value) : + _engine(engine), _value(std::move(value)) {} + static ScriptProgramQtWrapper* unwrap(ScriptProgramPointer val); + inline const QScriptProgram& toQtValue() const { return _value; } + +public: // ScriptProgram implementation + virtual ScriptSyntaxCheckResultPointer checkSyntax() const; + virtual QString fileName() const; + virtual QString sourceCode() const; + +private: // storage + QPointer _engine; + QScriptProgram _value; +}; + +class ScriptSyntaxCheckResultQtWrapper : public ScriptSyntaxCheckResult { +public: // construction + inline ScriptSyntaxCheckResultQtWrapper(QScriptSyntaxCheckResult&& value) : + _value(std::move(value)) {} + +public: // ScriptSyntaxCheckResult implementation + virtual int errorColumnNumber() const; + virtual int errorLineNumber() const; + virtual QString errorMessage() const; + virtual State state() const; + +private: // storage + QScriptSyntaxCheckResult _value; +}; + +#endif // hifi_ScriptValueQtWrapper_h \ No newline at end of file diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp new file mode 100644 index 00000000000..755d2556db0 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp @@ -0,0 +1,33 @@ +// +// ScriptValueIteratorQtWrapper.cpp +// libraries/script-engine/src +// +// Created by Heather Anderson on 8/29/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptValueIteratorQtWrapper.h" + +ScriptValue::PropertyFlags ScriptValueIteratorQtWrapper::flags() const { + return (ScriptValue::PropertyFlags)(int)_value.flags(); +} + +bool ScriptValueIteratorQtWrapper::hasNext() const { + return _value.hasNext(); +} + +QString ScriptValueIteratorQtWrapper::name() const { + return _value.name(); +} + +void ScriptValueIteratorQtWrapper::next() { + _value.next(); +} + +ScriptValuePointer ScriptValueIteratorQtWrapper::value() const { + QScriptValue result = _value.value(); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h new file mode 100644 index 00000000000..53b377dd761 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h @@ -0,0 +1,41 @@ +// +// ScriptValueIteratorQtWrapper.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 8/29/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptValueIteratorQtWrapper_h +#define hifi_ScriptValueIteratorQtWrapper_h + +//#include +#include + +#include "../ScriptValueIterator.h" +#include "ScriptEngineQtScript.h" +#include "ScriptValueQtWrapper.h" + +class ScriptValueIteratorQtWrapper : public ScriptValueIterator { +public: // construction + inline ScriptValueIteratorQtWrapper(ScriptEngineQtScript* engine, const ScriptValuePointer& object) : + _engine(engine), _value(ScriptValueQtWrapper::fullUnwrap(engine, object)) {} + inline ScriptValueIteratorQtWrapper(ScriptEngineQtScript* engine, const QScriptValue& object) : + _engine(engine), _value(object) {} + +public: // ScriptValueIterator implementation + virtual ScriptValue::PropertyFlags flags() const; + virtual bool hasNext() const; + virtual QString name() const; + virtual void next(); + virtual ScriptValuePointer value() const; + +private: // storage + QPointer _engine; + QScriptValueIterator _value; +}; + +#endif // hifi_ScriptValueIteratorQtWrapper_h \ No newline at end of file diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp new file mode 100644 index 00000000000..0bdb8245496 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp @@ -0,0 +1,216 @@ +// +// ScriptValueQtWrapper.cpp +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/16/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptValueQtWrapper.h" + +#include "ScriptValueIteratorQtWrapper.h" + +ScriptValueQtWrapper* ScriptValueQtWrapper::unwrap(ScriptValuePointer val) { + if (!val) { + return nullptr; + } + + return dynamic_cast(val.data()); +} + +QScriptValue ScriptValueQtWrapper::fullUnwrap(const ScriptValuePointer& value) const { + if (!value) { + return QScriptValue(); + } + ScriptValueQtWrapper* unwrapped = unwrap(value); + if (unwrapped) { + return unwrapped->toQtValue(); + } + QVariant varValue = value->toVariant(); + return static_cast(_engine)->newVariant(varValue); +} + +QScriptValue ScriptValueQtWrapper::fullUnwrap(ScriptEngineQtScript* engine, const ScriptValuePointer& value) { + if (!value) { + return QScriptValue(); + } + ScriptValueQtWrapper* unwrapped = unwrap(value); + if (unwrapped) { + return unwrapped->toQtValue(); + } + QVariant varValue = value->toVariant(); + return static_cast(engine)->newVariant(varValue); +} + +ScriptValuePointer ScriptValueQtWrapper::call(const ScriptValuePointer& thisObject, const ScriptValueList& args) { + QScriptValue qThis = fullUnwrap(thisObject); + QScriptValueList qArgs; + for (ScriptValueList::const_iterator iter = args.begin(); iter != args.end(); ++iter) { + qArgs.push_back(fullUnwrap(*iter)); + } + QScriptValue result = _value.call(qThis, qArgs); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptValuePointer ScriptValueQtWrapper::call(const ScriptValuePointer& thisObject, const ScriptValuePointer& arguments) { + QScriptValue qThis = fullUnwrap(thisObject); + QScriptValue qArgs = fullUnwrap(arguments); + QScriptValue result = _value.call(qThis, qArgs); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptValuePointer ScriptValueQtWrapper::construct(const ScriptValueList& args) { + QScriptValueList qArgs; + for (ScriptValueList::const_iterator iter = args.begin(); iter != args.end(); ++iter) { + qArgs.push_back(fullUnwrap(*iter)); + } + QScriptValue result = _value.construct(qArgs); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptValuePointer ScriptValueQtWrapper::construct(const ScriptValuePointer& arguments) { + QScriptValue unwrapped = fullUnwrap(arguments); + QScriptValue result = _value.construct(unwrapped); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptValuePointer ScriptValueQtWrapper::data() const { + QScriptValue result = _value.data(); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptEnginePointer ScriptValueQtWrapper::engine() const { + if (!_engine) { + return ScriptEnginePointer(); + } + return _engine->sharedFromThis(); +} + +ScriptValueIteratorPointer ScriptValueQtWrapper::newIterator() { + return ScriptValueIteratorPointer(new ScriptValueIteratorQtWrapper(_engine, _value)); +} + +ScriptValuePointer ScriptValueQtWrapper::property(const QString& name, const ResolveFlags& mode) const { + QScriptValue result = _value.property(name, (QScriptValue::ResolveFlags)(int)mode); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +ScriptValuePointer ScriptValueQtWrapper::property(quint32 arrayIndex, const ResolveFlags& mode) const { + QScriptValue result = _value.property(arrayIndex, (QScriptValue::ResolveFlags)(int)mode); + return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); +} + +void ScriptValueQtWrapper::setData(const ScriptValuePointer& value) { + QScriptValue unwrapped = fullUnwrap(value); + _value.setData(unwrapped); +} + +void ScriptValueQtWrapper::setProperty(const QString& name, const ScriptValuePointer& value, const PropertyFlags& flags) { + QScriptValue unwrapped = fullUnwrap(value); + _value.setProperty(name, unwrapped, (QScriptValue::PropertyFlags)(int)flags); +} + +void ScriptValueQtWrapper::setProperty(quint32 arrayIndex, const ScriptValuePointer& value, const PropertyFlags& flags) { + QScriptValue unwrapped = fullUnwrap(value); + _value.setProperty(arrayIndex, unwrapped, (QScriptValue::PropertyFlags)(int)flags); +} + +void ScriptValueQtWrapper::setPrototype(const ScriptValuePointer& prototype) { + ScriptValueQtWrapper* unwrappedPrototype = unwrap(prototype); + if (unwrappedPrototype) { + _value.setPrototype(unwrappedPrototype->toQtValue()); + } +} + +bool ScriptValueQtWrapper::strictlyEquals(const ScriptValuePointer& other) const { + ScriptValueQtWrapper* unwrappedOther = unwrap(other); + return unwrappedOther ? _value.strictlyEquals(unwrappedOther->toQtValue()) : false; +} + +bool ScriptValueQtWrapper::toBool() const { + return _value.toBool(); +} + +qint32 ScriptValueQtWrapper::toInt32() const { + return _value.toInt32(); +} + +double ScriptValueQtWrapper::toInteger() const { + return _value.toInteger(); +} + +double ScriptValueQtWrapper::toNumber() const { + return _value.toNumber(); +} + +QString ScriptValueQtWrapper::toString() const { + return _value.toString(); +} + +quint16 ScriptValueQtWrapper::toUInt16() const { + return _value.toUInt16(); +} + +quint32 ScriptValueQtWrapper::toUInt32() const { + return _value.toUInt32(); +} + +QVariant ScriptValueQtWrapper::toVariant() const { + return _value.toVariant(); +} + +QObject* ScriptValueQtWrapper::toQObject() const { + return _value.toQObject(); +} + +bool ScriptValueQtWrapper::equalsInternal(const ScriptValuePointer& other) const { + ScriptValueQtWrapper* unwrappedOther = unwrap(other); + return unwrappedOther ? _value.equals(unwrappedOther->toQtValue()) : false; +} + +bool ScriptValueQtWrapper::isArrayInternal() const { + return _value.isArray(); +} + +bool ScriptValueQtWrapper::isBoolInternal() const { + return _value.isBool(); +} + +bool ScriptValueQtWrapper::isErrorInternal() const { + return _value.isError(); +} + +bool ScriptValueQtWrapper::isFunctionInternal() const { + return _value.isFunction(); +} + +bool ScriptValueQtWrapper::isNumberInternal() const { + return _value.isNumber(); +} + +bool ScriptValueQtWrapper::isNullInternal() const { + return _value.isNull(); +} + +bool ScriptValueQtWrapper::isObjectInternal() const { + return _value.isObject(); +} + +bool ScriptValueQtWrapper::isStringInternal() const { + return _value.isString(); +} + +bool ScriptValueQtWrapper::isUndefinedInternal() const { + return _value.isUndefined(); +} + +bool ScriptValueQtWrapper::isValidInternal() const { + return _value.isValid(); +} + +bool ScriptValueQtWrapper::isVariantInternal() const { + return _value.isVariant(); +} diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h new file mode 100644 index 00000000000..2a4c8c842d4 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h @@ -0,0 +1,86 @@ +// +// ScriptValueQtWrapper.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 5/16/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptValueQtWrapper_h +#define hifi_ScriptValueQtWrapper_h + +#include +#include + +#include + +#include "../ScriptValue.h" +#include "ScriptEngineQtScript.h" + +class ScriptValueQtWrapper : public ScriptValue { +public: // construction + inline ScriptValueQtWrapper(ScriptEngineQtScript* engine, const QScriptValue& value) : + _engine(engine), _value(value) {} + inline ScriptValueQtWrapper(ScriptEngineQtScript* engine, QScriptValue&& value) : + _engine(engine), _value(std::move(value)) {} + static ScriptValueQtWrapper* unwrap(ScriptValuePointer val); + inline const QScriptValue& toQtValue() const { return _value; } + static QScriptValue fullUnwrap(ScriptEngineQtScript* engine, const ScriptValuePointer& value); + +public: // ScriptValue implementation + virtual ScriptValuePointer call(const ScriptValuePointer& thisObject = ScriptValuePointer(), + const ScriptValueList& args = ScriptValueList()); + virtual ScriptValuePointer call(const ScriptValuePointer& thisObject, const ScriptValuePointer& arguments); + virtual ScriptValuePointer construct(const ScriptValueList& args = ScriptValueList()); + virtual ScriptValuePointer construct(const ScriptValuePointer& arguments); + virtual ScriptValuePointer data() const; + virtual ScriptEnginePointer engine() const; + virtual ScriptValueIteratorPointer newIterator(); + virtual ScriptValuePointer property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const; + virtual ScriptValuePointer property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const; + virtual void setData(const ScriptValuePointer& val); + virtual void setProperty(const QString& name, + const ScriptValuePointer& value, + const PropertyFlags& flags = KeepExistingFlags); + virtual void setProperty(quint32 arrayIndex, + const ScriptValuePointer& value, + const PropertyFlags& flags = KeepExistingFlags); + virtual void setPrototype(const ScriptValuePointer& prototype); + virtual bool strictlyEquals(const ScriptValuePointer& other) const; + + virtual bool toBool() const; + virtual qint32 toInt32() const; + virtual double toInteger() const; + virtual double toNumber() const; + virtual QString toString() const; + virtual quint16 toUInt16() const; + virtual quint32 toUInt32() const; + virtual QVariant toVariant() const; + virtual QObject* toQObject() const; + +protected: // ScriptValue implementation + virtual bool equalsInternal(const ScriptValuePointer& other) const; + virtual bool isArrayInternal() const; + virtual bool isBoolInternal() const; + virtual bool isErrorInternal() const; + virtual bool isFunctionInternal() const; + virtual bool isNumberInternal() const; + virtual bool isNullInternal() const; + virtual bool isObjectInternal() const; + virtual bool isStringInternal() const; + virtual bool isUndefinedInternal() const; + virtual bool isValidInternal() const; + virtual bool isVariantInternal() const; + +private: // helper functions + QScriptValue fullUnwrap(const ScriptValuePointer& value) const; + +private: // storage + QPointer _engine; + QScriptValue _value; +}; + +#endif // hifi_ScriptValueQtWrapper_h \ No newline at end of file diff --git a/libraries/script-engine-qtscript/src/TypedArrayPrototype.cpp b/libraries/script-engine/src/qtscript/TypedArrayPrototype.cpp similarity index 100% rename from libraries/script-engine-qtscript/src/TypedArrayPrototype.cpp rename to libraries/script-engine/src/qtscript/TypedArrayPrototype.cpp diff --git a/libraries/script-engine-qtscript/src/TypedArrayPrototype.h b/libraries/script-engine/src/qtscript/TypedArrayPrototype.h similarity index 100% rename from libraries/script-engine-qtscript/src/TypedArrayPrototype.h rename to libraries/script-engine/src/qtscript/TypedArrayPrototype.h diff --git a/libraries/script-engine-qtscript/src/TypedArrays.cpp b/libraries/script-engine/src/qtscript/TypedArrays.cpp similarity index 100% rename from libraries/script-engine-qtscript/src/TypedArrays.cpp rename to libraries/script-engine/src/qtscript/TypedArrays.cpp diff --git a/libraries/script-engine-qtscript/src/TypedArrays.h b/libraries/script-engine/src/qtscript/TypedArrays.h similarity index 100% rename from libraries/script-engine-qtscript/src/TypedArrays.h rename to libraries/script-engine/src/qtscript/TypedArrays.h From 87bb35c22f61cb26580df7fc3a65f54e6b3b40e5 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 29 Aug 2021 23:02:08 -0700 Subject: [PATCH 04/34] adding basic script-engine documentation --- libraries/script-engine/src/PointerEvent.h | 6 +++ libraries/script-engine/src/ScriptContext.h | 9 +++- libraries/script-engine/src/ScriptEngine.h | 10 ++++- .../script-engine/src/ScriptEngineCast.h | 5 +++ libraries/script-engine/src/ScriptProgram.h | 9 +++- libraries/script-engine/src/ScriptValue.h | 10 ++++- .../script-engine/src/ScriptValueIterator.h | 8 +++- .../script-engine/src/ScriptValueUtils.h | 5 +++ libraries/script-engine/src/Scriptable.h | 8 +++- .../src/VariantMapToScriptValue.h | 5 +++ .../src/qtscript/ArrayBufferClass.h | 2 +- .../src/qtscript/ArrayBufferPrototype.h | 2 +- .../src/qtscript/ArrayBufferViewClass.h | 2 +- .../src/qtscript/DataViewClass.h | 2 +- .../src/qtscript/DataViewPrototype.h | 2 +- .../src/qtscript/ScriptContextQtWrapper.h | 8 +++- .../src/qtscript/ScriptEngineQtScript.h | 42 ++++--------------- .../src/qtscript/ScriptProgramQtWrapper.h | 8 +++- .../qtscript/ScriptValueIteratorQtWrapper.h | 10 ++++- .../src/qtscript/ScriptValueQtWrapper.h | 8 +++- .../src/qtscript/TypedArrayPrototype.h | 2 +- .../script-engine/src/qtscript/TypedArrays.h | 2 +- 22 files changed, 111 insertions(+), 54 deletions(-) diff --git a/libraries/script-engine/src/PointerEvent.h b/libraries/script-engine/src/PointerEvent.h index 197b144bdba..3fd83ce5108 100644 --- a/libraries/script-engine/src/PointerEvent.h +++ b/libraries/script-engine/src/PointerEvent.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_PointerEvent_h #define hifi_PointerEvent_h @@ -22,6 +25,7 @@ class ScriptEngine; class ScriptValue; using ScriptValuePointer = QSharedPointer; +/// Represents a 2D or 3D pointer to the scripting engine. Exposed as PointerEvent class PointerEvent { public: enum Button { @@ -95,3 +99,5 @@ QDebug& operator<<(QDebug& dbg, const PointerEvent& p); Q_DECLARE_METATYPE(PointerEvent) #endif // hifi_PointerEvent_h + +/// @} diff --git a/libraries/script-engine/src/ScriptContext.h b/libraries/script-engine/src/ScriptContext.h index dbdc6a5e370..bb1f70da632 100644 --- a/libraries/script-engine/src/ScriptContext.h +++ b/libraries/script-engine/src/ScriptContext.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptContext_h #define hifi_ScriptContext_h @@ -25,6 +28,7 @@ using ScriptFunctionContextPointer = QSharedPointer; using ScriptEnginePointer = QSharedPointer; using ScriptValuePointer = QSharedPointer; +/// [ScriptInterface] Provides an engine-independent interface for QScriptContextInfo class ScriptFunctionContext { public: enum FunctionType { @@ -41,6 +45,7 @@ class ScriptFunctionContext { virtual int lineNumber() const = 0; }; +/// [ScriptInterface] Provides an engine-independent interface for QScriptContext class ScriptContext { public: virtual int argumentCount() const = 0; @@ -55,4 +60,6 @@ class ScriptContext { virtual ScriptValuePointer throwValue(const ScriptValuePointer& value) = 0; }; -#endif // hifi_ScriptContext_h \ No newline at end of file +#endif // hifi_ScriptContext_h + +/// @} diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 2fd92343d7e..e9efded5cd1 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -10,6 +10,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptEngine_h #define hifi_ScriptEngine_h @@ -31,8 +34,9 @@ using ScriptEnginePointer = QSharedPointer; using ScriptProgramPointer = QSharedPointer; using ScriptValuePointer = QSharedPointer; -Q_DECLARE_METATYPE(ScriptEnginePointer) +Q_DECLARE_METATYPE(ScriptEnginePointer); +/// [ScriptInterface] Provides an engine-independent interface for QScriptEngine class ScriptEngine { public: typedef ScriptValuePointer (*FunctionSignature)(ScriptContext*, ScriptEngine*); @@ -125,7 +129,7 @@ class ScriptEngine { virtual bool convert(const ScriptValuePointer& value, int type, void* ptr) = 0; virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df, const ScriptValuePointer& prototype) = 0; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptEngine::QObjectWrapOptions) +Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptEngine::QObjectWrapOptions); ScriptEnginePointer newScriptEngine(ScriptManager* manager = nullptr); @@ -154,3 +158,5 @@ QThread* ScriptEngine::thread() const { */ #endif // hifi_ScriptEngine_h + +/// @} diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h index 9a5c8a47c6a..22221e74a4c 100644 --- a/libraries/script-engine/src/ScriptEngineCast.h +++ b/libraries/script-engine/src/ScriptEngineCast.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptEngineCast_h #define hifi_ScriptEngineCast_h @@ -99,3 +102,5 @@ int scriptRegisterSequenceMetaType(ScriptEngine* engine, } #endif // hifi_ScriptEngineCast_h + +/// @} diff --git a/libraries/script-engine/src/ScriptProgram.h b/libraries/script-engine/src/ScriptProgram.h index 1c49f042d69..8301532c431 100644 --- a/libraries/script-engine/src/ScriptProgram.h +++ b/libraries/script-engine/src/ScriptProgram.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptProgram_h #define hifi_ScriptProgram_h @@ -19,6 +22,7 @@ class ScriptSyntaxCheckResult; using ScriptProgramPointer = QSharedPointer; using ScriptSyntaxCheckResultPointer = QSharedPointer; +/// [ScriptInterface] Provides an engine-independent interface for QScriptProgram class ScriptProgram { public: virtual ScriptSyntaxCheckResultPointer checkSyntax() const = 0; @@ -26,6 +30,7 @@ class ScriptProgram { virtual QString sourceCode() const = 0; }; +/// [ScriptInterface] Provides an engine-independent interface for QScriptSyntaxCheckResult class ScriptSyntaxCheckResult { public: enum State @@ -42,4 +47,6 @@ class ScriptSyntaxCheckResult { virtual State state() const = 0; }; -#endif // hifi_ScriptProgram_h \ No newline at end of file +#endif // hifi_ScriptProgram_h + +/// @} diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h index 67a8f8eb607..7b774045460 100644 --- a/libraries/script-engine/src/ScriptValue.h +++ b/libraries/script-engine/src/ScriptValue.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptValue_h #define hifi_ScriptValue_h @@ -26,6 +29,7 @@ using ScriptValuePointer = QSharedPointer; using ScriptValueList = QList; using ScriptValueIteratorPointer = QSharedPointer; +/// [ScriptInterface] Provides an engine-independent interface for QScriptValue class ScriptValue { public: enum ResolveFlag @@ -107,7 +111,7 @@ class ScriptValue { virtual bool isValidInternal() const = 0; virtual bool isVariantInternal() const = 0; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptValue::PropertyFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptValue::PropertyFlags); bool ScriptValue::equals(const ScriptValuePointer& other) const { if (this == NULL || !other) { @@ -205,4 +209,6 @@ void ScriptValue::setProperty(quint32 arrayIndex, const TYP& value, const Proper template T scriptvalue_cast(const ScriptValuePointer& value); -#endif // hifi_ScriptValue_h \ No newline at end of file +#endif // hifi_ScriptValue_h + +/// @} diff --git a/libraries/script-engine/src/ScriptValueIterator.h b/libraries/script-engine/src/ScriptValueIterator.h index cea07de415a..2222a457a86 100644 --- a/libraries/script-engine/src/ScriptValueIterator.h +++ b/libraries/script-engine/src/ScriptValueIterator.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptValueIterator_h #define hifi_ScriptValueIterator_h @@ -20,6 +23,7 @@ class ScriptValueIterator; using ScriptValueIteratorPointer = QSharedPointer; +/// [ScriptInterface] Provides an engine-independent interface for QScriptValueIterator class ScriptValueIterator { public: virtual ScriptValue::PropertyFlags flags() const = 0; @@ -29,4 +33,6 @@ class ScriptValueIterator { virtual ScriptValuePointer value() const = 0; }; -#endif // hifi_ScriptValueIterator_h \ No newline at end of file +#endif // hifi_ScriptValueIterator_h + +/// @} diff --git a/libraries/script-engine/src/ScriptValueUtils.h b/libraries/script-engine/src/ScriptValueUtils.h index bd6e4d2cb31..c65561ff7af 100644 --- a/libraries/script-engine/src/ScriptValueUtils.h +++ b/libraries/script-engine/src/ScriptValueUtils.h @@ -11,6 +11,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptValueUtils_h #define hifi_ScriptValueUtils_h @@ -260,3 +263,5 @@ void promiseFromScriptValue(const ScriptValuePointer& object, std::shared_ptr& promise); #endif // #define hifi_ScriptValueUtils_h + +/// @} diff --git a/libraries/script-engine/src/Scriptable.h b/libraries/script-engine/src/Scriptable.h index b6d08a2bfe8..d9e8403e27f 100644 --- a/libraries/script-engine/src/Scriptable.h +++ b/libraries/script-engine/src/Scriptable.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_Scriptable_h #define hifi_Scriptable_h @@ -21,6 +24,7 @@ class ScriptValue; using ScriptEnginePointer = QSharedPointer; using ScriptValuePointer = QSharedPointer; +/// [ScriptInterface] Provides an engine-independent interface for QScriptable class Scriptable { public: static inline ScriptEnginePointer engine(); @@ -56,4 +60,6 @@ ScriptValuePointer Scriptable::argument(int index) { return scriptContext->argument(index); } -#endif // hifi_Scriptable_h \ No newline at end of file +#endif // hifi_Scriptable_h + +/// @} diff --git a/libraries/script-engine/src/VariantMapToScriptValue.h b/libraries/script-engine/src/VariantMapToScriptValue.h index 2700decedd3..3093938d371 100644 --- a/libraries/script-engine/src/VariantMapToScriptValue.h +++ b/libraries/script-engine/src/VariantMapToScriptValue.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #include #include "ScriptValue.h" #include "ScriptEngine.h" @@ -16,3 +19,5 @@ ScriptValuePointer variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEngine); ScriptValuePointer variantMapToScriptValue(QVariantMap& variantMap, ScriptEngine& scriptEngine); ScriptValuePointer variantListToScriptValue(QVariantList& variantList, ScriptEngine& scriptEngine); + +/// @} diff --git a/libraries/script-engine/src/qtscript/ArrayBufferClass.h b/libraries/script-engine/src/qtscript/ArrayBufferClass.h index 2d7cf06be54..c9efce1ad49 100644 --- a/libraries/script-engine/src/qtscript/ArrayBufferClass.h +++ b/libraries/script-engine/src/qtscript/ArrayBufferClass.h @@ -26,7 +26,7 @@ class ScriptEngineQtScript; -/// Implements the ArrayBuffer scripting class +/// [QtScript] Implements the ArrayBuffer scripting class class ArrayBufferClass : public QObject, public QScriptClass { Q_OBJECT public: diff --git a/libraries/script-engine/src/qtscript/ArrayBufferPrototype.h b/libraries/script-engine/src/qtscript/ArrayBufferPrototype.h index 324f3176609..1fc5948f6bd 100644 --- a/libraries/script-engine/src/qtscript/ArrayBufferPrototype.h +++ b/libraries/script-engine/src/qtscript/ArrayBufferPrototype.h @@ -18,7 +18,7 @@ #include #include -/// The javascript functions associated with an ArrayBuffer instance prototype +/// [QtScript] The javascript functions associated with an ArrayBuffer instance prototype class ArrayBufferPrototype : public QObject, public QScriptable { Q_OBJECT public: diff --git a/libraries/script-engine/src/qtscript/ArrayBufferViewClass.h b/libraries/script-engine/src/qtscript/ArrayBufferViewClass.h index ffeb1c4d604..e5c40d8e440 100644 --- a/libraries/script-engine/src/qtscript/ArrayBufferViewClass.h +++ b/libraries/script-engine/src/qtscript/ArrayBufferViewClass.h @@ -29,7 +29,7 @@ static const QString BUFFER_PROPERTY_NAME = "buffer"; static const QString BYTE_OFFSET_PROPERTY_NAME = "byteOffset"; static const QString BYTE_LENGTH_PROPERTY_NAME = "byteLength"; -/// The base class containing common code for ArrayBuffer views +/// [QtScript] The base class containing common code for ArrayBuffer views class ArrayBufferViewClass : public QObject, public QScriptClass { Q_OBJECT public: diff --git a/libraries/script-engine/src/qtscript/DataViewClass.h b/libraries/script-engine/src/qtscript/DataViewClass.h index 5ad14793209..8b587bbd06a 100644 --- a/libraries/script-engine/src/qtscript/DataViewClass.h +++ b/libraries/script-engine/src/qtscript/DataViewClass.h @@ -17,7 +17,7 @@ #include "ArrayBufferViewClass.h" -/// Implements the DataView scripting class +/// [QtScript] Implements the DataView scripting class class DataViewClass : public ArrayBufferViewClass { Q_OBJECT public: diff --git a/libraries/script-engine/src/qtscript/DataViewPrototype.h b/libraries/script-engine/src/qtscript/DataViewPrototype.h index b4d9462e8f6..3f395516c13 100644 --- a/libraries/script-engine/src/qtscript/DataViewPrototype.h +++ b/libraries/script-engine/src/qtscript/DataViewPrototype.h @@ -18,7 +18,7 @@ #include #include -/// The javascript functions associated with a DataView instance prototype +/// [QtScript] The javascript functions associated with a DataView instance prototype class DataViewPrototype : public QObject, public QScriptable { Q_OBJECT public: diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h index 993fb69a81f..229a5b71025 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptContextQtWrapper_h #define hifi_ScriptContextQtWrapper_h @@ -23,6 +26,7 @@ class ScriptEngineQtScript; class ScriptValue; using ScriptValuePointer = QSharedPointer; +/// [QtScript] Implements ScriptContext for QtScript and translates calls for QScriptContextInfo class ScriptContextQtWrapper : public ScriptContext { public: // construction inline ScriptContextQtWrapper(ScriptEngineQtScript* engine, QScriptContext* context) : _engine(engine), _context(context) {} @@ -60,4 +64,6 @@ class ScriptFunctionContextQtWrapper : public ScriptFunctionContext { QScriptContextInfo _value; }; -#endif // hifi_ScriptContextQtWrapper_h \ No newline at end of file +#endif // hifi_ScriptContextQtWrapper_h + +/// @} diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index bb7a3a4017e..fa3d274d148 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -10,6 +10,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptEngineQtScript_h #define hifi_ScriptEngineQtScript_h @@ -35,40 +38,9 @@ class ScriptManager; using ScriptEngineQtScriptPointer = QSharedPointer; using ScriptContextQtPointer = QSharedPointer; -Q_DECLARE_METATYPE(ScriptEngineQtScriptPointer) - -/*@jsdoc - * The Script API provides facilities for working with scripts. - * - * @namespace Script - * - * @hifi-interface - * @hifi-client-entity - * @hifi-avatar - * @hifi-server-entity - * @hifi-assignment-client - * - * @property {string} context - The context that the script is running in: - *
    - *
  • "client": An Interface or avatar script.
  • - *
  • "entity_client": A client entity script.
  • - *
  • "entity_server": A server entity script.
  • - *
  • "agent": An assignment client script.
  • - *
- * Read-only. - * @property {string} type - The type of script that is running: - *
    - *
  • "client": An Interface script.
  • - *
  • "entity_client": A client entity script.
  • - *
  • "avatar": An avatar script.
  • - *
  • "entity_server": A server entity script.
  • - *
  • "agent": An assignment client script.
  • - *
- * Read-only. - * @property {string} filename - The filename of the script file. - * Read-only. - * @property {Script.ResourceBuckets} ExternalPaths - External resource buckets. - */ +Q_DECLARE_METATYPE(ScriptEngineQtScriptPointer); + +/// [QtScript] Implements ScriptEngine for QtScript and translates calls for QScriptEngine class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public QEnableSharedFromThis { Q_OBJECT @@ -467,3 +439,5 @@ public slots: }; #endif // hifi_ScriptEngineQtScript_h + +/// @} diff --git a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h index b09c58b0d94..dca9c9d83a8 100644 --- a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptProgramQtWrapper_h #define hifi_ScriptProgramQtWrapper_h @@ -18,6 +21,7 @@ #include "../ScriptProgram.h" #include "ScriptEngineQtScript.h" +/// [QtScript] Implements ScriptProgram for QtScript and translates calls for QScriptProgram class ScriptProgramQtWrapper : public ScriptProgram { public: // construction inline ScriptProgramQtWrapper(ScriptEngineQtScript* engine, const QScriptProgram& value) : @@ -52,4 +56,6 @@ class ScriptSyntaxCheckResultQtWrapper : public ScriptSyntaxCheckResult { QScriptSyntaxCheckResult _value; }; -#endif // hifi_ScriptValueQtWrapper_h \ No newline at end of file +#endif // hifi_ScriptValueQtWrapper_h + +/// @} diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h index 53b377dd761..ee5d20ef1e1 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h @@ -9,16 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptValueIteratorQtWrapper_h #define hifi_ScriptValueIteratorQtWrapper_h -//#include +#include #include #include "../ScriptValueIterator.h" #include "ScriptEngineQtScript.h" #include "ScriptValueQtWrapper.h" +/// [QtScript] Implements ScriptValueIterator for QtScript and translates calls for QScriptValueIterator class ScriptValueIteratorQtWrapper : public ScriptValueIterator { public: // construction inline ScriptValueIteratorQtWrapper(ScriptEngineQtScript* engine, const ScriptValuePointer& object) : @@ -38,4 +42,6 @@ class ScriptValueIteratorQtWrapper : public ScriptValueIterator { QScriptValueIterator _value; }; -#endif // hifi_ScriptValueIteratorQtWrapper_h \ No newline at end of file +#endif // hifi_ScriptValueIteratorQtWrapper_h + +/// @} diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h index 2a4c8c842d4..5ac1dea9430 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/// @addtogroup ScriptEngine +/// @{ + #ifndef hifi_ScriptValueQtWrapper_h #define hifi_ScriptValueQtWrapper_h @@ -20,6 +23,7 @@ #include "../ScriptValue.h" #include "ScriptEngineQtScript.h" +/// [QtScript] Implements ScriptValue for QtScript and translates calls for QScriptValue class ScriptValueQtWrapper : public ScriptValue { public: // construction inline ScriptValueQtWrapper(ScriptEngineQtScript* engine, const QScriptValue& value) : @@ -83,4 +87,6 @@ class ScriptValueQtWrapper : public ScriptValue { QScriptValue _value; }; -#endif // hifi_ScriptValueQtWrapper_h \ No newline at end of file +#endif // hifi_ScriptValueQtWrapper_h + +/// @} diff --git a/libraries/script-engine/src/qtscript/TypedArrayPrototype.h b/libraries/script-engine/src/qtscript/TypedArrayPrototype.h index e2fac3c8d9f..ff0ea2fec65 100644 --- a/libraries/script-engine/src/qtscript/TypedArrayPrototype.h +++ b/libraries/script-engine/src/qtscript/TypedArrayPrototype.h @@ -19,7 +19,7 @@ #include #include -/// The javascript functions associated with a TypedArray instance prototype +/// [QtScript] The javascript functions associated with a TypedArray instance prototype class TypedArrayPrototype : public QObject, public QScriptable { Q_OBJECT public: diff --git a/libraries/script-engine/src/qtscript/TypedArrays.h b/libraries/script-engine/src/qtscript/TypedArrays.h index 452cdbd4ee0..0595ba3c630 100644 --- a/libraries/script-engine/src/qtscript/TypedArrays.h +++ b/libraries/script-engine/src/qtscript/TypedArrays.h @@ -30,7 +30,7 @@ static const QString UINT_32_ARRAY_CLASS_NAME = "Uint32Array"; static const QString FLOAT_32_ARRAY_CLASS_NAME = "Float32Array"; static const QString FLOAT_64_ARRAY_CLASS_NAME = "Float64Array"; -/// Implements the TypedArray scripting class +/// [QtScript] Implements the TypedArray scripting class class TypedArray : public ArrayBufferViewClass { Q_OBJECT public: From dd34b774c844b89abb0f37aeab355472e0dee122 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Tue, 31 Aug 2021 18:09:08 -0700 Subject: [PATCH 05/34] shifting classes around and adding static initializers to resolve dependencies on scripting-engine (and drop dependencies from scripting-engine) --- assignment-client/src/Agent.cpp | 2 +- interface/src/Application.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 4 +- libraries/animation/CMakeLists.txt | 2 - libraries/animation/src/AnimationObject.cpp | 5 + libraries/animation/src/Rig.cpp | 37 +- libraries/audio/src/AudioEffectOptions.cpp | 8 + .../src/AudioScriptingInterface.cpp | 16 +- .../src/AudioScriptingInterface.h | 6 +- .../src/ScriptAudioInjector.cpp | 16 +- .../src/ScriptAudioInjector.h | 4 +- libraries/avatars/src/AvatarData.cpp | 11 +- libraries/avatars/src/ScriptAvatarData.cpp | 19 + .../src/controllers/ScriptingInterface.cpp | 21 ++ .../src/ModelScriptingInterface.cpp | 20 +- .../src/ModelScriptingInterface.h | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 2 +- libraries/entities/CMakeLists.txt | 1 - .../entities/src/EntityScriptingInterface.cpp | 170 +++++++++ .../entities/src/EntityScriptingInterface.h | 8 +- .../GraphicsScriptingInterface.cpp | 2 +- libraries/physics/src/ObjectDynamic.h | 2 +- libraries/recording/CMakeLists.txt | 2 +- .../RecordingScriptingInterface.cpp | 20 +- .../recording}/RecordingScriptingInterface.h | 6 +- libraries/script-engine/CMakeLists.txt | 17 +- .../src/EntitiesScriptEngineProvider.h | 2 +- .../src/EntityItemID.cpp | 8 +- .../src/EntityItemID.h | 2 +- .../src/EntityScriptUtils.h | 2 +- libraries/script-engine/src/ScriptCache.cpp | 1 + libraries/script-engine/src/ScriptCache.h | 2 +- libraries/script-engine/src/ScriptEngine.h | 4 +- libraries/script-engine/src/ScriptManager.cpp | 331 +++--------------- libraries/script-engine/src/ScriptManager.h | 47 ++- .../script-engine/src/ScriptValueUtils.cpp | 3 +- .../src/qtscript/ScriptContextQtAgent.cpp | 2 +- .../src/qtscript/ScriptContextQtAgent.h | 2 +- .../src/qtscript/ScriptContextQtWrapper.cpp | 2 +- .../src/qtscript/ScriptContextQtWrapper.h | 2 +- .../src/qtscript/ScriptEngineQtScript.cpp | 8 +- .../src/qtscript/ScriptEngineQtScript.h | 2 +- .../src/qtscript/ScriptProgramQtWrapper.cpp | 2 +- .../src/qtscript/ScriptProgramQtWrapper.h | 2 +- .../qtscript/ScriptValueIteratorQtWrapper.cpp | 2 +- .../qtscript/ScriptValueIteratorQtWrapper.h | 2 +- .../src/qtscript/ScriptValueQtWrapper.cpp | 2 +- .../src/qtscript/ScriptValueQtWrapper.h | 2 +- libraries/ui/CMakeLists.txt | 2 - libraries/ui/src/ui/QmlWrapper.h | 2 +- .../ui/src/ui/ToolbarScriptingInterface.cpp | 4 +- plugins/JSAPIExample/CMakeLists.txt | 2 - plugins/JSAPIExample/src/JSAPIExample.cpp | 4 +- 53 files changed, 456 insertions(+), 395 deletions(-) rename libraries/{script-engine => audio}/src/AudioScriptingInterface.cpp (91%) rename libraries/{script-engine => audio}/src/AudioScriptingInterface.h (99%) rename libraries/{script-engine => audio}/src/ScriptAudioInjector.cpp (79%) rename libraries/{script-engine => audio}/src/ScriptAudioInjector.h (98%) rename libraries/{script-engine => entities-renderer}/src/ModelScriptingInterface.cpp (96%) rename libraries/{script-engine => entities-renderer}/src/ModelScriptingInterface.h (99%) rename libraries/{script-engine/src => recording/src/recording}/RecordingScriptingInterface.cpp (97%) rename libraries/{script-engine/src => recording/src/recording}/RecordingScriptingInterface.h (99%) rename libraries/{entities => script-engine}/src/EntitiesScriptEngineProvider.h (96%) rename libraries/{entities => script-engine}/src/EntityItemID.cpp (94%) rename libraries/{entities => script-engine}/src/EntityItemID.h (98%) rename libraries/{networking => script-engine}/src/EntityScriptUtils.h (96%) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 1512c27d365..f74a533464f 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -59,7 +59,7 @@ #include "entities/AssignmentParentFinder.h" #include "AssignmentDynamicFactory.h" -#include "RecordingScriptingInterface.h" +#include #include "AbstractAudioInterface.h" #include "AgentScriptingInterface.h" diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1b5f63f1591..afa9e802fec 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -131,7 +131,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 58e4062e2f3..9732f78948b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include #include #include @@ -439,7 +439,7 @@ void MyAvatar::enableHandTouchForID(const QUuid& entityID) { } void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) { - ScriptValuePointer value = engine->newQObject(this, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); + ScriptValuePointer value = engine->newQObject(this, ScriptEngine::QtOwnership); engine->globalObject()->setProperty("MyAvatar", value); ScriptValuePointer driveKeys = engine->newObject(); diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 9d843caaac1..a18f6c24827 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -1,8 +1,6 @@ set(TARGET_NAME animation) setup_hifi_library(Network) link_hifi_libraries(shared graphics model-serializers script-engine) -include_hifi_library_headers(animation) -include_hifi_library_headers(entities) include_hifi_library_headers(gpu) include_hifi_library_headers(hfm) include_hifi_library_headers(image) diff --git a/libraries/animation/src/AnimationObject.cpp b/libraries/animation/src/AnimationObject.cpp index 20ecead184b..09ac8114b9a 100644 --- a/libraries/animation/src/AnimationObject.cpp +++ b/libraries/animation/src/AnimationObject.cpp @@ -13,10 +13,15 @@ #include #include +#include #include #include "AnimationCache.h" +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { + registerAnimationTypes(manager->engine().data()); +}); + QStringList AnimationObject::getJointNames() const { return scriptvalue_cast(thisObject())->getJointNames(); } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index a99f2e6071c..9cc06847b05 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1652,14 +1652,35 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh rig->animationStateHandlerResult(identifier, result); } }; - // invokeMethod makes a copy of the args, and copies of AnimVariantMap do copy the underlying map, so this will correctly capture - // the state of _animVars and allow continued changes to _animVars in this thread without conflict. - QMetaObject::invokeMethod(function->engine()->manager(), "callAnimationStateHandler", Qt::QueuedConnection, - Q_ARG(ScriptValuePointer, function), - Q_ARG(AnimVariantMap, _animVars), - Q_ARG(QStringList, value.propertyNames), - Q_ARG(bool, value.useNames), - Q_ARG(AnimVariantResultHandler, handleResult)); + + { + // make references to the parameters for the lambda here, but let the lambda be the one to take the copies + // Copies of AnimVariantMap do copy the underlying map, so this will correctly capture + // the state of _animVars and allow continued changes to _animVars in this thread without conflict. + const AnimVariantMap& animVars = _animVars; + ScriptEnginePointer engine = function->engine(); + const QStringList& names = value.propertyNames; + bool useNames = value.useNames; + + QMetaObject::invokeMethod( + engine->manager(), + [function, animVars, names, useNames, handleResult, engine] { + ScriptValuePointer javascriptParameters = animVars.animVariantMapToScriptValue(engine.get(), names, useNames); + ScriptValueList callingArguments; + callingArguments << javascriptParameters; + ScriptValuePointer result = function->call(ScriptValuePointer(), callingArguments); + + // validate result from callback function. + if (result->isValid() && result->isObject()) { + handleResult(result); + } else { + qCWarning(animation) << "Rig::updateAnimationStateHandlers invalid return argument from " + "callback, expected an object"; + } + }, + Qt::QueuedConnection); + } + // It turns out that, for thread-safety reasons, ScriptEngine::callAnimationStateHandler will invoke itself if called from other // than the script thread. Thus the above _could_ be replaced with an ordinary call, which will then trigger the same // invokeMethod as is done explicitly above. However, the script-engine library depends on this animation library, not vice versa. diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 94533a230e9..dc7dd38b23a 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -12,8 +12,16 @@ #include #include +#include #include +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { + auto scriptEngine = manager->engine().data(); + + ScriptValuePointer audioEffectOptionsConstructorValue = scriptEngine->newFunction(AudioEffectOptions::constructor); + scriptEngine->globalObject()->setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); +}); + static const QString BANDWIDTH_HANDLE = "bandwidth"; static const QString PRE_DELAY_HANDLE = "preDelay"; static const QString LATE_DELAY_HANDLE = "lateDelay"; diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp similarity index 91% rename from libraries/script-engine/src/AudioScriptingInterface.cpp rename to libraries/audio/src/AudioScriptingInterface.cpp index 797a5b525d2..f84efada047 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -16,9 +16,19 @@ #include #include "ScriptAudioInjector.h" -#include "ScriptEngine.h" -#include "ScriptEngineCast.h" -#include "ScriptEngineLogging.h" +#include +#include +#include +#include + + +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager){ + auto scriptEngine = manager->engine().data(); + + registerAudioMetaTypes(scriptEngine); + scriptEngine->registerGlobalObject("Audio", DependencyManager::get().data()); +}); + void registerAudioMetaTypes(ScriptEngine* engine) { scriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h similarity index 99% rename from libraries/script-engine/src/AudioScriptingInterface.h rename to libraries/audio/src/AudioScriptingInterface.h index d6c9853f9c9..0c0e3144fa5 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -15,10 +15,10 @@ #ifndef hifi_AudioScriptingInterface_h #define hifi_AudioScriptingInterface_h -#include -#include +#include "AbstractAudioInterface.h" +#include "AudioInjector.h" #include -#include +#include "Sound.h" class ScriptAudioInjector; class ScriptEngine; diff --git a/libraries/script-engine/src/ScriptAudioInjector.cpp b/libraries/audio/src/ScriptAudioInjector.cpp similarity index 79% rename from libraries/script-engine/src/ScriptAudioInjector.cpp rename to libraries/audio/src/ScriptAudioInjector.cpp index 324a463ef2f..67a761c149a 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.cpp +++ b/libraries/audio/src/ScriptAudioInjector.cpp @@ -1,6 +1,6 @@ // // ScriptAudioInjector.cpp -// libraries/script-engine/src +// libraries/audio/src // // Created by Stephen Birarda on 2015-02-11. // Copyright 2015 High Fidelity, Inc. @@ -11,9 +11,17 @@ #include "ScriptAudioInjector.h" -#include "ScriptEngine.h" -#include "ScriptEngineLogging.h" -#include "ScriptValue.h" +#include +#include +#include +#include +#include + +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { + auto scriptEngine = manager->engine().data(); + + scriptRegisterMetaType(scriptEngine, injectorToScriptValue, injectorFromScriptValue); +}); ScriptValuePointer injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in) { // The AudioScriptingInterface::playSound method can return null, so we need to account for that. diff --git a/libraries/script-engine/src/ScriptAudioInjector.h b/libraries/audio/src/ScriptAudioInjector.h similarity index 98% rename from libraries/script-engine/src/ScriptAudioInjector.h rename to libraries/audio/src/ScriptAudioInjector.h index 2ca50af744d..30be70e7acb 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.h +++ b/libraries/audio/src/ScriptAudioInjector.h @@ -1,6 +1,6 @@ // // ScriptAudioInjector.h -// libraries/script-engine/src +// libraries/audio/src // // Created by Stephen Birarda on 2015-02-11. // Copyright 2015 High Fidelity, Inc. @@ -18,7 +18,7 @@ #include #include -#include +#include "AudioInjectorManager.h" class ScriptEngine; class ScriptValue; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 6651b95d9eb..fa967cfcdf0 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -37,13 +37,14 @@ #include #include #include +#include #include +#include #include #include #include #include #include -#include #include "AvatarLogging.h" #include "AvatarTraits.h" @@ -66,6 +67,14 @@ static const float DEFAULT_AVATAR_DENSITY = 1000.0f; // density of water #define ASSERT(COND) do { if (!(COND)) { abort(); } } while(0) +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { + auto scriptEngine = manager->engine().data(); + + registerAvatarTypes(scriptEngine); + scriptRegisterMetaType(scriptEngine, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue); + scriptRegisterMetaType(scriptEngine, AvatarEntityMapToScriptValue, AvatarEntityMapFromScriptValue); +}); + size_t AvatarDataPacket::maxFaceTrackerInfoSize(size_t numBlendshapeCoefficients) { return FACE_TRACKER_INFO_SIZE + numBlendshapeCoefficients * sizeof(float); } diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index a67af18c40c..6f322190c09 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -11,6 +11,25 @@ #include "ScriptAvatarData.h" +#include +#include + +ScriptValuePointer avatarDataToScriptValue(ScriptEngine* engine, ScriptAvatarData* const& in) { + return engine->newQObject(in, ScriptEngine::ScriptOwnership); +} + +void avatarDataFromScriptValue(const ScriptValuePointer& object, ScriptAvatarData*& out) { + // This is not implemented because there are no slots/properties that take an AvatarSharedPointer from a script + assert(false); + out = nullptr; +} + +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { + auto scriptEngine = manager->engine().data(); + + scriptRegisterMetaType(scriptEngine, avatarDataToScriptValue, avatarDataFromScriptValue); +}); + ScriptAvatarData::ScriptAvatarData(AvatarSharedPointer avatarData) : _avatarData(avatarData) { diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index e9a831859da..396e7cb5d42 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -25,6 +25,27 @@ #include "InputDevice.h" #include "InputRecorder.h" +#include +#include +#include +#include + +Q_DECLARE_METATYPE(controller::InputController*) +//static int inputControllerPointerId = qRegisterMetaType(); + +ScriptValuePointer inputControllerToScriptValue(ScriptEngine* engine, controller::InputController* const& in) { + return engine->newQObject(in, ScriptEngine::QtOwnership); +} + +void inputControllerFromScriptValue(const ScriptValuePointer& object, controller::InputController*& out) { + out = qobject_cast(object->toQObject()); +} + +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { + auto scriptEngine = manager->engine().data(); + + scriptRegisterMetaType(scriptEngine, inputControllerToScriptValue, inputControllerFromScriptValue); +}); static QRegularExpression SANITIZE_NAME_EXPRESSION{ "[\\(\\)\\.\\s]" }; diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/entities-renderer/src/ModelScriptingInterface.cpp similarity index 96% rename from libraries/script-engine/src/ModelScriptingInterface.cpp rename to libraries/entities-renderer/src/ModelScriptingInterface.cpp index a9b72db8cb7..ca9fd45242d 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/entities-renderer/src/ModelScriptingInterface.cpp @@ -1,6 +1,6 @@ // // ModelScriptingInterface.cpp -// libraries/script-engine/src +// libraries/entities-renderer/src // // Created by Seth Alves on 2017-1-27. // Copyright 2017 High Fidelity, Inc. @@ -11,12 +11,18 @@ #include "ModelScriptingInterface.h" #include -#include "ScriptEngine.h" -#include "ScriptEngineCast.h" -#include "ScriptEngineLogging.h" -#include "ScriptManager.h" -#include "ScriptValueUtils.h" -#include "OBJWriter.h" +#include +#include +#include +#include +#include +#include + +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { + auto scriptEngine = manager->engine().data(); + + scriptEngine->registerGlobalObject("Model", new ModelScriptingInterface(manager)); +}); ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) { _modelScriptEngine = qobject_cast(parent)->engine(); diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/entities-renderer/src/ModelScriptingInterface.h similarity index 99% rename from libraries/script-engine/src/ModelScriptingInterface.h rename to libraries/entities-renderer/src/ModelScriptingInterface.h index f750ba6ae09..61958fae388 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.h +++ b/libraries/entities-renderer/src/ModelScriptingInterface.h @@ -1,6 +1,6 @@ // // ModelScriptingInterface.h -// libraries/script-engine/src +// libraries/entities-renderer/src // // Created by Seth Alves on 2017-1-27. // Copyright 2017 High Fidelity, Inc. diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5c8374b9379..a14af230168 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include "ModelScriptingInterface.h" #include #include #include diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index dcd5a665b9e..bf612b156e5 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,7 +1,6 @@ set(TARGET_NAME entities) setup_hifi_library(Network) target_include_directories(${TARGET_NAME} PRIVATE "${OPENSSL_INCLUDE_DIR}") -include_hifi_library_headers(animation) include_hifi_library_headers(hfm) include_hifi_library_headers(model-serializers) include_hifi_library_headers(gpu) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6b4ba52f205..ba338e6084d 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -48,6 +48,36 @@ const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}"; const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}"; +static void staticScriptInitializer(ScriptManager* manager) { + auto scriptEngine = manager->engine().data(); + + auto entityScriptingInterface = DependencyManager::get(); + entityScriptingInterface->init(); + auto ifacePtr = entityScriptingInterface.data(); // using this when we don't want to leak a reference + + registerMetaTypes(scriptEngine); + + scriptRegisterMetaType(scriptEngine, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue); + scriptRegisterMetaType(scriptEngine, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); + scriptRegisterMetaType(scriptEngine, EntityPropertyInfoToScriptValue, EntityPropertyInfoFromScriptValue); + scriptRegisterMetaType(scriptEngine, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); + scriptRegisterMetaType(scriptEngine, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); + + scriptEngine->registerGlobalObject("Entities", entityScriptingInterface.data()); + scriptEngine->registerFunction("Entities", "getMultipleEntityProperties", EntityScriptingInterface::getMultipleEntityProperties); + + // "The return value of QObject::sender() is not valid when the slot is called via a Qt::DirectConnection from a thread + // different from this object's thread. Do not use this function in this type of scenario." + // so... yay lambdas everywhere to get the sender + manager->connect( + manager, &ScriptManager::attachDefaultEventHandlers, entityScriptingInterface.data(), + [ifacePtr, manager] { ifacePtr->attachDefaultEventHandlers(manager); }, + Qt::DirectConnection); + manager->connect(manager, &ScriptManager::releaseEntityPacketSenderMessages, entityScriptingInterface.data(), + &EntityScriptingInterface::releaseEntityPacketSenderMessages, Qt::DirectConnection); +} +STATIC_SCRIPT_INITIALIZER(staticScriptInitializer); + EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) : _entityTree(nullptr), _bidOnSimulationOwnership(bidOnSimulationOwnership) @@ -67,6 +97,146 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership PacketReceiver::makeSourcedListenerReference(this, &EntityScriptingInterface::handleEntityScriptCallMethodPacket)); } +void EntityScriptingInterface::releaseEntityPacketSenderMessages(bool wait) { + EntityEditPacketSender* entityPacketSender = getEntityPacketSender(); + if (entityPacketSender->serversExist()) { + // release the queue of edit entity messages. + entityPacketSender->releaseQueuedMessages(); + + // since we're in non-threaded mode, call process so that the packets are sent + if (!entityPacketSender->isThreaded()) { + if (!wait) { + entityPacketSender->process(); + } else { + // wait here till the edit packet sender is completely done sending + while (entityPacketSender->hasPacketsToSend()) { + entityPacketSender->process(); + QCoreApplication::processEvents(); + } + } + } else { + // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders? + } + } +} + + +void EntityScriptingInterface::attachDefaultEventHandlers(ScriptManager* manager) { + // Connect up ALL the handlers to the global entities object's signals. + // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) + + // Bug? These handlers are deleted when entityID is deleted, which is nice. + // But if they are created by an entity script on a different entity, should they also be deleted when the entity script unloads? + // E.g., suppose a bow has an entity script that causes arrows to be created with a potential lifetime greater than the bow, + // and that the entity script adds (e.g., collision) handlers to the arrows. Should those handlers fire if the bow is unloaded? + // Also, what about when the entity script is REloaded? + // For now, we are leaving them around. Changing that would require some non-trivial digging around to find the + // handlers that were added while a given currentEntityIdentifier was in place. I don't think this is dangerous. Just perhaps unexpected. -HRS + connect(this, &EntityScriptingInterface::deletingEntity, manager, + [manager](const EntityItemID& entityID) { manager->removeAllEventHandlers(entityID); }); + + // Two common cases of event handler, differing only in argument signature. + + /*@jsdoc + * Called when an entity event occurs on an entity as registered with {@link Script.addEventHandler}. + * @callback Script~entityEventCallback + * @param {Uuid} entityID - The ID of the entity the event has occured on. + */ + using SingleEntityHandler = std::function; + auto makeSingleEntityHandler = [manager](QString eventName) -> SingleEntityHandler { + return [manager, eventName](const EntityItemID& entityItemID) { + manager->forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(manager->engine().data()) }); + }; + }; + + /*@jsdoc + * Called when a pointer event occurs on an entity as registered with {@link Script.addEventHandler}. + * @callback Script~pointerEventCallback + * @param {Uuid} entityID - The ID of the entity the event has occurred on. + * @param {PointerEvent} pointerEvent - Details of the event. + */ + using PointerHandler = std::function; + auto makePointerHandler = [manager](QString eventName) -> PointerHandler { + return [manager, eventName](const EntityItemID& entityItemID, const PointerEvent& event) { + if (!EntityTree::areEntityClicksCaptured()) { + ScriptEngine* engine = manager->engine().data(); + manager->forwardHandlerCall(entityItemID, eventName, + { entityItemID.toScriptValue(engine), event.toScriptValue(engine) }); + } + }; + }; + + /*@jsdoc + * Called when a collision event occurs on an entity as registered with {@link Script.addEventHandler}. + * @callback Script~collisionEventCallback + * @param {Uuid} entityA - The ID of one entity in the collision. + * @param {Uuid} entityB - The ID of the other entity in the collision. + * @param {Collision} collisionEvent - Details of the collision. + */ + using CollisionHandler = std::function; + auto makeCollisionHandler = [manager](QString eventName) -> CollisionHandler { + return [manager, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { + ScriptEngine* engine = manager->engine().data(); + manager->forwardHandlerCall(idA, eventName, + { idA.toScriptValue(engine), idB.toScriptValue(engine), + collisionToScriptValue(engine, collision) }); + }; + }; + + /*@jsdoc + *

The name of an entity event. When the entity event occurs, any function that has been registered for that event + * via {@link Script.addEventHandler} is called with parameters per the entity event.

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Event NameCallback TypeEntity Event
"enterEntity"{@link Script~entityEventCallback|entityEventCallback}{@link Entities.enterEntity}
"leaveEntity"{@link Script~entityEventCallback|entityEventCallback}{@link Entities.leaveEntity}
"mousePressOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.mousePressOnEntity}
"mouseMoveOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.mouseMoveOnEntity}
"mouseReleaseOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.mouseReleaseOnEntity}
"clickDownOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.clickDownOnEntity}
"holdingClickOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.holdingClickOnEntity}
"clickReleaseOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.clickReleaseOnEntity}
"hoverEnterEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.hoverEnterEntity}
"hoverOverEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.hoverOverEntity}
"hoverLeaveEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.hoverLeaveEntity}
"collisionWithEntity"{@link Script~collisionEventCallback|collisionEventCallback}{@link Entities.collisionWithEntity}
+ * @typedef {string} Script.EntityEvent + */ + connect(this, &EntityScriptingInterface::enterEntity, manager, makeSingleEntityHandler("enterEntity")); + connect(this, &EntityScriptingInterface::leaveEntity, manager, makeSingleEntityHandler("leaveEntity")); + + connect(this, &EntityScriptingInterface::mousePressOnEntity, manager, makePointerHandler("mousePressOnEntity")); + connect(this, &EntityScriptingInterface::mouseMoveOnEntity, manager, makePointerHandler("mouseMoveOnEntity")); + connect(this, &EntityScriptingInterface::mouseReleaseOnEntity, manager, makePointerHandler("mouseReleaseOnEntity")); + + connect(this, &EntityScriptingInterface::clickDownOnEntity, manager, makePointerHandler("clickDownOnEntity")); + connect(this, &EntityScriptingInterface::holdingClickOnEntity, manager, makePointerHandler("holdingClickOnEntity")); + connect(this, &EntityScriptingInterface::clickReleaseOnEntity, manager, makePointerHandler("clickReleaseOnEntity")); + + connect(this, &EntityScriptingInterface::hoverEnterEntity, manager, makePointerHandler("hoverEnterEntity")); + connect(this, &EntityScriptingInterface::hoverOverEntity, manager, makePointerHandler("hoverOverEntity")); + connect(this, &EntityScriptingInterface::hoverLeaveEntity, manager, makePointerHandler("hoverLeaveEntity")); + + connect(this, &EntityScriptingInterface::collisionWithEntity, manager, makeCollisionHandler("collisionWithEntity")); +} + void EntityScriptingInterface::queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties) { getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 1d7c21644a7..854ce4943c4 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -27,7 +27,7 @@ #include #include "PointerEvent.h" #include -#include "ScriptManager.h" +#include #include "PolyVoxEntityItem.h" #include "LineEntityItem.h" @@ -2540,7 +2540,13 @@ public slots: } }; +private: + void attachDefaultEventHandlers(ScriptManager* manager); // called on first call to Script.addEventHandler + friend void staticScriptInitializer(ScriptManager* manager); + private slots: + void releaseEntityPacketSenderMessages(bool wait); + void handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode); void onAddingEntity(EntityItem* entity); void onDeletingEntity(EntityItem* entity); diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index cdce0658e07..08f531bdb29 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -323,7 +323,7 @@ namespace scriptable { if (!object) { return engine->nullValue(); } - return engine->newQObject(object, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::AutoCreateDynamicProperties); + return engine->newQObject(object, ScriptEngine::QtOwnership, ScriptEngine::AutoCreateDynamicProperties); }, [](const ScriptValuePointer& value, QPointer& out) { auto obj = value->toQObject(); diff --git a/libraries/physics/src/ObjectDynamic.h b/libraries/physics/src/ObjectDynamic.h index 49fa615b889..96c2f225bbd 100644 --- a/libraries/physics/src/ObjectDynamic.h +++ b/libraries/physics/src/ObjectDynamic.h @@ -23,7 +23,7 @@ #include "ObjectMotionState.h" #include "BulletUtil.h" -#include "EntityDynamicInterface.h" +#include class ObjectDynamic : public EntityDynamicInterface, public ReadWriteLockable { diff --git a/libraries/recording/CMakeLists.txt b/libraries/recording/CMakeLists.txt index 5821688eb06..ef357fdd5d7 100644 --- a/libraries/recording/CMakeLists.txt +++ b/libraries/recording/CMakeLists.txt @@ -4,6 +4,6 @@ set(TARGET_NAME recording) setup_hifi_library() # use setup_hifi_library macro to setup our project and link appropriate Qt modules -link_hifi_libraries(shared networking) +link_hifi_libraries(shared networking script-engine) GroupSources("src/recording") diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/recording/src/recording/RecordingScriptingInterface.cpp similarity index 97% rename from libraries/script-engine/src/RecordingScriptingInterface.cpp rename to libraries/recording/src/recording/RecordingScriptingInterface.cpp index e6cab50b240..f712a4c813c 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/recording/src/recording/RecordingScriptingInterface.cpp @@ -20,16 +20,16 @@ #include #include #include -#include -#include -#include -#include -#include - -#include "ScriptEngine.h" -#include "ScriptEngineLogging.h" -#include "ScriptManager.h" -#include "ScriptValue.h" +#include "Deck.h" +#include "Recorder.h" +#include "Clip.h" +#include "Frame.h" +#include "ClipCache.h" + +#include +#include +#include +#include using namespace recording; diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/recording/src/recording/RecordingScriptingInterface.h similarity index 99% rename from libraries/script-engine/src/RecordingScriptingInterface.h rename to libraries/recording/src/recording/RecordingScriptingInterface.h index 73fdfb3c961..f645e197007 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/recording/src/recording/RecordingScriptingInterface.h @@ -19,9 +19,9 @@ #include #include -#include -#include -#include +#include "ClipCache.h" +#include "Forward.h" +#include "Frame.h" class ScriptValue; using ScriptValuePointer = QSharedPointer; diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index ae4d16db52c..83ba2c63cca 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME script-engine) # FIXME Move undo scripting interface to application and remove Widgets -setup_hifi_library(Gui Network Script ScriptTools WebSockets) +setup_hifi_library(Network Script WebSockets) target_zlib() if (NOT ANDROID) @@ -8,21 +8,6 @@ if (NOT ANDROID) endif () link_hifi_libraries(shaders) -include_hifi_library_headers(animation) -include_hifi_library_headers(audio) -include_hifi_library_headers(avatars) -include_hifi_library_headers(controllers) -include_hifi_library_headers(entities) -include_hifi_library_headers(gpu) -include_hifi_library_headers(hfm) -include_hifi_library_headers(image) -include_hifi_library_headers(ktx) -include_hifi_library_headers(graphics) -include_hifi_library_headers(material-networking) -include_hifi_library_headers(model-networking) -include_hifi_library_headers(model-serializers) include_hifi_library_headers(networking) include_hifi_library_headers(octree) -include_hifi_library_headers(procedural) -include_hifi_library_headers(recording) include_hifi_library_headers(shared) diff --git a/libraries/entities/src/EntitiesScriptEngineProvider.h b/libraries/script-engine/src/EntitiesScriptEngineProvider.h similarity index 96% rename from libraries/entities/src/EntitiesScriptEngineProvider.h rename to libraries/script-engine/src/EntitiesScriptEngineProvider.h index 100c17df5f3..fffdbe4c766 100644 --- a/libraries/entities/src/EntitiesScriptEngineProvider.h +++ b/libraries/script-engine/src/EntitiesScriptEngineProvider.h @@ -1,6 +1,6 @@ // // EntitiesScriptEngineProvider.h -// libraries/entities/src +// libraries/script-engine/src // // Created by Brad Hefta-Gaub on Sept. 18, 2015 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/entities/src/EntityItemID.cpp b/libraries/script-engine/src/EntityItemID.cpp similarity index 94% rename from libraries/entities/src/EntityItemID.cpp rename to libraries/script-engine/src/EntityItemID.cpp index 874a0fcd531..275637dfa84 100644 --- a/libraries/entities/src/EntityItemID.cpp +++ b/libraries/script-engine/src/EntityItemID.cpp @@ -1,6 +1,6 @@ // // EntityItemID.cpp -// libraries/entities/src +// libraries/script-engine/src // // Created by Brad Hefta-Gaub on 12/4/13. // Copyright 2013 High Fidelity, Inc. @@ -17,9 +17,9 @@ #include #include -#include "RegisteredMetaTypes.h" -#include -#include +#include +#include "ScriptValue.h" +#include "ScriptValueUtils.h" int entityItemIDTypeID = qRegisterMetaType(); diff --git a/libraries/entities/src/EntityItemID.h b/libraries/script-engine/src/EntityItemID.h similarity index 98% rename from libraries/entities/src/EntityItemID.h rename to libraries/script-engine/src/EntityItemID.h index 499493fa10f..72a1bc90c73 100644 --- a/libraries/entities/src/EntityItemID.h +++ b/libraries/script-engine/src/EntityItemID.h @@ -1,6 +1,6 @@ // // EntityItemID.h -// libraries/entities/src +// libraries/script-engine/src // // Created by Brad Hefta-Gaub on 12/4/13. // Copyright 2013 High Fidelity, Inc. diff --git a/libraries/networking/src/EntityScriptUtils.h b/libraries/script-engine/src/EntityScriptUtils.h similarity index 96% rename from libraries/networking/src/EntityScriptUtils.h rename to libraries/script-engine/src/EntityScriptUtils.h index 15b056f0d24..4dad88f8924 100644 --- a/libraries/networking/src/EntityScriptUtils.h +++ b/libraries/script-engine/src/EntityScriptUtils.h @@ -1,6 +1,6 @@ // // EntityScriptUtils.h -// libraries/networking/src +// libraries/script-engine/src // // Created by Ryan Huffman on 2017/01/13 // Copyright 2017 High Fidelity, Inc. diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index 0b63803a333..bd2e5dfa781 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include "ScriptEngines.h" diff --git a/libraries/script-engine/src/ScriptCache.h b/libraries/script-engine/src/ScriptCache.h index 03d815e4ada..019cdac6f91 100644 --- a/libraries/script-engine/src/ScriptCache.h +++ b/libraries/script-engine/src/ScriptCache.h @@ -16,7 +16,7 @@ #define hifi_ScriptCache_h #include -#include +#include using contentAvailableCallback = std::function; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index e9efded5cd1..8488873680b 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -50,11 +50,11 @@ class ScriptEngine { }; enum QObjectWrapOption { - ExcludeChildObjects = 0x0001, // The script object will not expose child objects as properties. + //ExcludeChildObjects = 0x0001, // The script object will not expose child objects as properties. ExcludeSuperClassMethods = 0x0002, // The script object will not expose signals and slots inherited from the superclass. ExcludeSuperClassProperties = 0x0004, // The script object will not expose properties inherited from the superclass. ExcludeSuperClassContents = 0x0006, // Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties - ExcludeDeleteLater = 0x0010, // The script object will not expose the QObject::deleteLater() slot. + //ExcludeDeleteLater = 0x0010, // The script object will not expose the QObject::deleteLater() slot. ExcludeSlots = 0x0020, // The script object will not expose the QObject's slots. AutoCreateDynamicProperties = 0x0100, // Properties that don't already exist in the QObject will be created as dynamic properties of that object, rather than as properties of the script object. PreferExistingWrapperObject = 0x0200, // If a wrapper object with the requested configuration already exists, return that object. diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index cda16c27acc..5388f728592 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -24,55 +24,36 @@ #include #include -#include -#include -#include -#include - -#include -#include - #include -#include #include -#include -#include -#include #include -#include #include -#include +#include #include +#include +#include +#include #include #include #include -#include -#include -#include - -#include -#include -#include "AudioScriptingInterface.h" #include "AssetScriptingInterface.h" #include "BatchLoader.h" #include "EventTypes.h" #include "FileScriptingInterface.h" // unzip project #include "MenuItemProperties.h" -#include "ScriptAudioInjector.h" -#include "ScriptAvatarData.h" #include "ScriptCache.h" #include "ScriptContext.h" -#include "ScriptEngineCast.h" -#include "ScriptEngineLogging.h" #include "XMLHttpRequestClass.h" #include "WebSocketClass.h" -#include "RecordingScriptingInterface.h" +#include "ScriptEngine.h" +#include "ScriptEngineCast.h" +#include "ScriptEngineLogging.h" #include "ScriptEngines.h" #include "StackTestScriptingInterface.h" -#include "ModelScriptingInterface.h" #include "ScriptValue.h" #include "ScriptValueIterator.h" +#include "ScriptValueUtils.h" #include @@ -94,8 +75,6 @@ const QString ScriptManager::SCRIPT_BACKTRACE_SEP{ "\n " }; static const int MAX_MODULE_ID_LENGTH { 4096 }; static const int MAX_DEBUG_VALUE_LENGTH { 80 }; -static const ScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = - ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects; static const ScriptValue::PropertyFlags READONLY_PROP_FLAGS{ ScriptValue::ReadOnly | ScriptValue::Undeletable }; static const ScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS{ READONLY_PROP_FLAGS | ScriptValue::SkipInEnumeration }; @@ -108,6 +87,26 @@ int scriptManagerPointerMetaID = qRegisterMetaType(); Q_DECLARE_METATYPE(ExternalResource::Bucket); +// --- Static script initialization registry + +static ScriptManager::StaticInitializerNode* rootInitializer = nullptr; + +void ScriptManager::registerNewStaticInitializer(StaticInitializerNode* dest) { + // this function is assumed to be called on LoadLibrary, where we are explicitly operating in single-threaded mode + // Therefore there is no mutex or threadsafety here and the structure is assumed not to change after loading + dest->prev = rootInitializer; + rootInitializer = dest; +} +static void runStaticInitializers(ScriptManager* manager) { + ScriptManager::StaticInitializerNode* here = rootInitializer; + while (here != nullptr) { + (*here->init)(manager); + here = here->prev; + } +} + +// --- + static ScriptValuePointer debugPrint(ScriptContext* context, ScriptEngine* engine) { // assemble the message by concatenating our arguments QString message = ""; @@ -172,17 +171,6 @@ static ScriptValuePointer debugPrint(ScriptContext* context, ScriptEngine* engin return ScriptValuePointer(); } -Q_DECLARE_METATYPE(controller::InputController*) -//static int inputControllerPointerId = qRegisterMetaType(); - -ScriptValuePointer inputControllerToScriptValue(ScriptEngine* engine, controller::InputController* const& in) { - return engine->newQObject(in, ScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); -} - -void inputControllerFromScriptValue(const ScriptValuePointer& object, controller::InputController*& out) { - out = qobject_cast(object->toQObject()); -} - // FIXME Come up with a way to properly encode entity IDs in filename // The purpose of the following two function is to embed entity ids into entity script filenames // so that they show up in stacktraces @@ -522,28 +510,6 @@ void ScriptManager::clearDebugLogWindow() { emit clearDebugWindow(); } -// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of -// callAnimationStateHandler requires that the type be registered. -// These two are meaningful, if we ever do want to use them... -static ScriptValuePointer animVarMapToScriptValue(ScriptEngine* engine, const AnimVariantMap& parameters) { - QStringList unused; - return parameters.animVariantMapToScriptValue(engine, unused, false); -} -static void animVarMapFromScriptValue(const ScriptValuePointer& value, AnimVariantMap& parameters) { - parameters.animVariantMapFromScriptValue(value); -} -// ... while these two are not. But none of the four are ever used. -static ScriptValuePointer resultHandlerToScriptValue(ScriptEngine* engine, - const AnimVariantResultHandler& resultHandler) { - qCCritical(scriptengine) << "Attempt to marshall result handler to javascript"; - assert(false); - return ScriptValuePointer(); -} -static void resultHandlerFromScriptValue(const ScriptValuePointer& value, AnimVariantResultHandler& resultHandler) { - qCCritical(scriptengine) << "Attempt to marshall result handler from javascript"; - assert(false); -} - // Templated qScriptRegisterMetaType fails to compile with raw pointers using ScriptableResourceRawPtr = ScriptableResource*; @@ -562,13 +528,10 @@ static ScriptValuePointer scriptableResourceToScriptValue(ScriptEngine* engine, auto manager = engine->manager(); if (data && manager && !resource->isInScript()) { resource->setInScript(true); - QObject::connect(data.data(), SIGNAL(updateSize(qint64)), manager, SLOT(updateMemoryCost(qint64))); + QObject::connect(data.data(), &Resource::updateSize, manager, &ScriptManager::updateMemoryCost); } - auto object = engine->newQObject( - const_cast(resource), - ScriptEngine::ScriptOwnership, - DEFAULT_QOBJECT_WRAP_OPTIONS); + auto object = engine->newQObject(const_cast(resource), ScriptEngine::ScriptOwnership); return object; } @@ -602,22 +565,12 @@ static ScriptValuePointer createScriptableResourcePrototype(ScriptManagerPointer } auto prototypeState = engine->newQObject(state, ScriptEngine::QtOwnership, - ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeSlots | ScriptEngine::ExcludeSuperClassMethods); + ScriptEngine::ExcludeSlots | ScriptEngine::ExcludeSuperClassMethods); prototype->setProperty("State", prototypeState); return prototype; } -ScriptValuePointer avatarDataToScriptValue(ScriptEngine* engine, ScriptAvatarData* const& in) { - return engine->newQObject(in, ScriptEngine::ScriptOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); -} - -void avatarDataFromScriptValue(const ScriptValuePointer& object, ScriptAvatarData*& out) { - // This is not implemented because there are no slots/properties that take an AvatarSharedPointer from a script - assert(false); - out = nullptr; -} - ScriptValuePointer externalResourceBucketToScriptValue(ScriptEngine* engine, ExternalResource::Bucket const& in) { return engine->newValue((int)in); } @@ -666,27 +619,15 @@ void ScriptManager::init() { } _isInitialized = true; - auto scriptEngine = _engine.data(); + runStaticInitializers(this); - auto entityScriptingInterface = DependencyManager::get(); - entityScriptingInterface->init(); + auto scriptEngine = _engine.data(); // register various meta-types - registerMetaTypes(scriptEngine); registerMIDIMetaTypes(scriptEngine); registerEventTypes(scriptEngine); registerMenuItemProperties(scriptEngine); - registerAnimationTypes(scriptEngine); - registerAvatarTypes(scriptEngine); - registerAudioMetaTypes(scriptEngine); - - scriptRegisterMetaType(scriptEngine, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue); - scriptRegisterMetaType(scriptEngine, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); - scriptRegisterMetaType(scriptEngine, EntityPropertyInfoToScriptValue, EntityPropertyInfoFromScriptValue); - scriptRegisterMetaType(scriptEngine, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); - scriptRegisterMetaType(scriptEngine, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); - scriptRegisterMetaType(scriptEngine, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue); - scriptRegisterMetaType(scriptEngine, AvatarEntityMapToScriptValue, AvatarEntityMapFromScriptValue); + scriptRegisterSequenceMetaType>(scriptEngine); scriptRegisterSequenceMetaType>(scriptEngine); @@ -709,12 +650,6 @@ void ScriptManager::init() { */ scriptEngine->globalObject()->setProperty("print", scriptEngine->newFunction(debugPrint)); - ScriptValuePointer audioEffectOptionsConstructorValue = scriptEngine->newFunction(AudioEffectOptions::constructor); - scriptEngine->globalObject()->setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); - - scriptRegisterMetaType(scriptEngine, injectorToScriptValue, injectorFromScriptValue); - scriptRegisterMetaType(scriptEngine, inputControllerToScriptValue, inputControllerFromScriptValue); - scriptRegisterMetaType(scriptEngine, avatarDataToScriptValue, avatarDataFromScriptValue); scriptRegisterMetaType(scriptEngine, animationDetailsToScriptValue, animationDetailsFromScriptValue); scriptRegisterMetaType(scriptEngine, webSocketToScriptValue, webSocketFromScriptValue); scriptRegisterMetaType(scriptEngine, qWSCloseCodeToScriptValue, qWSCloseCodeFromScriptValue); @@ -737,13 +672,8 @@ void ScriptManager::init() { scriptRegisterMetaType(scriptEngine, externalResourceBucketToScriptValue, externalResourceBucketFromScriptValue); scriptEngine->registerEnum("Script.ExternalPaths", QMetaEnum::fromType()); - scriptEngine->registerGlobalObject("Audio", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("Midi", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("Entities", entityScriptingInterface.data()); - scriptEngine->registerFunction("Entities", "getMultipleEntityProperties", - EntityScriptingInterface::getMultipleEntityProperties); scriptEngine->registerGlobalObject("Quat", &_quatLibrary); scriptEngine->registerGlobalObject("Vec3", &_vec3Library); scriptEngine->registerGlobalObject("Mat4", &_mat4Library); @@ -762,9 +692,6 @@ void ScriptManager::init() { scriptEngine->registerFunction("console", "groupCollapsed", ConsoleScriptingInterface::groupCollapsed, 1); scriptEngine->registerFunction("console", "groupEnd", ConsoleScriptingInterface::groupEnd, 0); - scriptRegisterMetaType(scriptEngine, animVarMapToScriptValue, animVarMapFromScriptValue); - scriptRegisterMetaType(scriptEngine, resultHandlerToScriptValue, resultHandlerFromScriptValue); - // Scriptable cache access auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast(sharedFromThis())); scriptEngine->globalObject()->setProperty("Resource", resourcePrototype); @@ -779,7 +706,6 @@ void ScriptManager::init() { scriptEngine->registerGlobalObject("DebugDraw", &DebugDraw::getInstance()); - scriptEngine->registerGlobalObject("Model", new ModelScriptingInterface(this)); scriptRegisterMetaType(scriptEngine, meshToScriptValue, meshFromScriptValue); scriptRegisterMetaType(scriptEngine, meshesToScriptValue, meshesFromScriptValue); @@ -825,6 +751,22 @@ void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QStri } } } + +// Unregister all event handlers for the specified entityID (i.e. the entity is being removed) +void ScriptManager::removeAllEventHandlers(const EntityItemID& entityID) { + if (QThread::currentThread() != thread()) { +#ifdef THREAD_DEBUGGING + qCDebug(scriptengine) << "*** WARNING *** ScriptManager::removeAllEventHandlers() called on wrong thread [" << QThread::currentThread() << ", correct thread is " << thread() << " ], ignoring " + "entityID:" << entityID; +#endif + return; + } + + if (_registeredHandlers.contains(entityID)) { + _registeredHandlers.remove(entityID); + } +} + // Register the handler. void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler) { if (QThread::currentThread() != thread()) { @@ -843,117 +785,9 @@ void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& qCDebug(scriptengine) << "ScriptManager::addEventHandler() called on thread [" << QThread::currentThread() << "] entityID:" << entityID << " eventName : " << eventName; #endif - if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script... - // Connect up ALL the handlers to the global entities object's signals. - // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) - auto entities = DependencyManager::get(); - // Bug? These handlers are deleted when entityID is deleted, which is nice. - // But if they are created by an entity script on a different entity, should they also be deleted when the entity script unloads? - // E.g., suppose a bow has an entity script that causes arrows to be created with a potential lifetime greater than the bow, - // and that the entity script adds (e.g., collision) handlers to the arrows. Should those handlers fire if the bow is unloaded? - // Also, what about when the entity script is REloaded? - // For now, we are leaving them around. Changing that would require some non-trivial digging around to find the - // handlers that were added while a given currentEntityIdentifier was in place. I don't think this is dangerous. Just perhaps unexpected. -HRS - connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { - _registeredHandlers.remove(entityID); - }); - - // Two common cases of event handler, differing only in argument signature. - - /*@jsdoc - * Called when an entity event occurs on an entity as registered with {@link Script.addEventHandler}. - * @callback Script~entityEventCallback - * @param {Uuid} entityID - The ID of the entity the event has occured on. - */ - using SingleEntityHandler = std::function; - auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler { - return [this, eventName](const EntityItemID& entityItemID) { - forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(_engine.data()) }); - }; - }; - - /*@jsdoc - * Called when a pointer event occurs on an entity as registered with {@link Script.addEventHandler}. - * @callback Script~pointerEventCallback - * @param {Uuid} entityID - The ID of the entity the event has occurred on. - * @param {PointerEvent} pointerEvent - Details of the event. - */ - using PointerHandler = std::function; - auto makePointerHandler = [this](QString eventName) -> PointerHandler { - return [this, eventName](const EntityItemID& entityItemID, const PointerEvent& event) { - if (!EntityTree::areEntityClicksCaptured()) { - forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(_engine.data()), event.toScriptValue(_engine.data()) }); - } - }; - }; - - /*@jsdoc - * Called when a collision event occurs on an entity as registered with {@link Script.addEventHandler}. - * @callback Script~collisionEventCallback - * @param {Uuid} entityA - The ID of one entity in the collision. - * @param {Uuid} entityB - The ID of the other entity in the collision. - * @param {Collision} collisionEvent - Details of the collision. - */ - using CollisionHandler = std::function; - auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { - return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - forwardHandlerCall(idA, eventName, { idA.toScriptValue(_engine.data()), idB.toScriptValue(_engine.data()), - collisionToScriptValue(_engine.data(), collision) }); - }; - }; - - /*@jsdoc - *

The name of an entity event. When the entity event occurs, any function that has been registered for that event - * via {@link Script.addEventHandler} is called with parameters per the entity event.

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Event NameCallback TypeEntity Event
"enterEntity"{@link Script~entityEventCallback|entityEventCallback}{@link Entities.enterEntity}
"leaveEntity"{@link Script~entityEventCallback|entityEventCallback}{@link Entities.leaveEntity}
"mousePressOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.mousePressOnEntity}
"mouseMoveOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.mouseMoveOnEntity}
"mouseReleaseOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.mouseReleaseOnEntity}
"clickDownOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.clickDownOnEntity}
"holdingClickOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.holdingClickOnEntity}
"clickReleaseOnEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.clickReleaseOnEntity}
"hoverEnterEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.hoverEnterEntity}
"hoverOverEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.hoverOverEntity}
"hoverLeaveEntity"{@link Script~pointerEventCallback|pointerEventCallback}{@link Entities.hoverLeaveEntity}
"collisionWithEntity"{@link Script~collisionEventCallback|collisionEventCallback}{@link Entities.collisionWithEntity}
- * @typedef {string} Script.EntityEvent - */ - connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); - connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); - - connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makePointerHandler("mousePressOnEntity")); - connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makePointerHandler("mouseMoveOnEntity")); - connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makePointerHandler("mouseReleaseOnEntity")); - - connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makePointerHandler("clickDownOnEntity")); - connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makePointerHandler("holdingClickOnEntity")); - connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makePointerHandler("clickReleaseOnEntity")); - - connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makePointerHandler("hoverEnterEntity")); - connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makePointerHandler("hoverOverEntity")); - connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makePointerHandler("hoverLeaveEntity")); - - connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity")); + if (_registeredHandlers.count() == 0) { + // First time any per-entity handler has been added in this script... + emit attachDefaultEventHandlers(); } if (!_registeredHandlers.contains(entityID)) { _registeredHandlers[entityID] = RegisteredEventHandlers(); @@ -1008,9 +842,6 @@ void ScriptManager::run() { clock::time_point startTime = clock::now(); int thisFrame = 0; - auto nodeList = DependencyManager::get(); - auto entityScriptingInterface = DependencyManager::get(); - _lastUpdate = usecTimestampNow(); std::chrono::microseconds totalUpdates(0); @@ -1050,7 +881,7 @@ void ScriptManager::run() { QEventLoop loop; QTimer timer; timer.setSingleShot(true); - connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); timer.start(sleepFor.count()); loop.exec(); } else { @@ -1092,14 +923,8 @@ void ScriptManager::run() { break; } - if (!_isFinished && entityScriptingInterface->getEntityPacketSender()->serversExist()) { - // release the queue of edit entity messages. - entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) { - entityScriptingInterface->getEntityPacketSender()->process(); - } + if (!_isFinished) { + emit releaseEntityPacketSenderMessages(false); } qint64 now = usecTimestampNow(); @@ -1133,21 +958,7 @@ void ScriptManager::run() { stopAllTimers(); // make sure all our timers are stopped if the script is ending emit scriptEnding(); - if (entityScriptingInterface->getEntityPacketSender()->serversExist()) { - // release the queue of edit entity messages. - entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - if (!entityScriptingInterface->getEntityPacketSender()->isThreaded()) { - // wait here till the edit packet sender is completely done sending - while (entityScriptingInterface->getEntityPacketSender()->hasPacketsToSend()) { - entityScriptingInterface->getEntityPacketSender()->process(); - QCoreApplication::processEvents(); - } - } else { - // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders? - } - } + emit releaseEntityPacketSenderMessages(true); emit finished(_fileNameString, qSharedPointerCast(sharedFromThis())); @@ -1203,34 +1014,6 @@ void ScriptManager::stop(bool marshal) { } } -// Other threads can invoke this through invokeMethod, which causes the callback to be asynchronously executed in this script's thread. -void ScriptManager::callAnimationStateHandler(ScriptValuePointer callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler) { - if (QThread::currentThread() != thread()) { -#ifdef THREAD_DEBUGGING - qCDebug(scriptengine) << "*** WARNING *** ScriptManager::callAnimationStateHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; -#endif - QMetaObject::invokeMethod(this, "callAnimationStateHandler", - Q_ARG(ScriptValuePointer, callback), - Q_ARG(AnimVariantMap, parameters), - Q_ARG(QStringList, names), - Q_ARG(bool, useNames), - Q_ARG(AnimVariantResultHandler, resultHandler)); - return; - } - ScriptValuePointer javascriptParameters = parameters.animVariantMapToScriptValue(_engine.get(), names, useNames); - ScriptValueList callingArguments; - callingArguments << javascriptParameters; - assert(currentEntityIdentifier.isInvalidID()); // No animation state handlers from entity scripts. - ScriptValuePointer result = callback->call(ScriptValuePointer(), callingArguments); - - // validate result from callback function. - if (result->isValid() && result->isObject()) { - resultHandler(result); - } else { - qCWarning(scriptengine) << "ScriptManager::callAnimationStateHandler invalid return argument from callback, expected an object"; - } -} - void ScriptManager::updateMemoryCost(const qint64& deltaSize) { _engine->updateMemoryCost(deltaSize); } diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index 9ba23a96df5..5b54623c2be 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -32,10 +33,9 @@ #include #include -#include #include "EntityItemID.h" #include "EntitiesScriptEngineProvider.h" -#include +#include "EntityScriptUtils.h" #include #include @@ -105,6 +105,10 @@ class EntityScriptDetails { QUrl definingSandboxURL { QUrl("about:EntityScript") }; }; +// declare a static script initializer +#define STATIC_SCRIPT_INITIALIZER(init) \ + static ScriptManager::StaticInitializerNode static_script_initializer_(init); + /*@jsdoc * The Script API provides facilities for working with scripts. * @@ -161,12 +165,22 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi AGENT, AVATAR }; - Q_ENUM(Type) + Q_ENUM(Type); static int processLevelMaxRetries; ScriptManager(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine")); ~ScriptManager(); + // static initialization support + typedef void (*ScriptManagerInitializer)(ScriptManager*); + class StaticInitializerNode { + public: + ScriptManagerInitializer init; + StaticInitializerNode* prev; + inline StaticInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticInitializer(this); } + }; + static void registerNewStaticInitializer(StaticInitializerNode* dest); + /// run the script in a dedicated thread. This will have the side effect of evalulating /// the current script contents and calling run(). Callers will likely want to register the script with external /// services before calling this. @@ -619,6 +633,13 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi void setScriptEngines(QSharedPointer& scriptEngines) { _scriptEngines = scriptEngines; } + // call all the registered event handlers on an entity for the specified name. + void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, ScriptValueList eventHanderArgs); + + // remove all event handlers for the specified entityID (i.e. the entity is being removed) + void removeAllEventHandlers(const EntityItemID& entityID); + + /*@jsdoc * Gets the URL for an asset in an external resource bucket. (The location where the bucket is hosted may change over time * but this method will return the asset's current URL.) @@ -638,17 +659,6 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi public slots: - /*@jsdoc - * @function Script.callAnimationStateHandler - * @param {function} callback - Callback function. - * @param {object} parameters - Parameters. - * @param {string[]} names - Names. - * @param {boolean} useNames - Use names. - * @param {function} resultHandler - Result handler. - * @deprecated This function is deprecated and will be removed. - */ - void callAnimationStateHandler(ScriptValuePointer callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); - /*@jsdoc * @function Script.updateMemoryCost * @param {number} deltaSize - Delta size. @@ -849,6 +859,14 @@ public slots: */ void unhandledException(const ScriptValuePointer& exception); + // Triggered once before the first call to Script.addEventHandler happens on this ScriptManager + // connections assumed to use Qt::DirectConnection; not for use by scripts + void attachDefaultEventHandlers(); + + // Triggered repeatedly in the scripting loop to ensure entity edit messages get processed properly + // connections assumed to use Qt::DirectConnection; not for use by scripts + void releaseEntityPacketSenderMessages(bool wait); + protected: void init(); @@ -884,7 +902,6 @@ public slots: void stopTimer(QTimer* timer); QHash _registeredHandlers; - void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, ScriptValueList eventHanderArgs); /*@jsdoc * @function Script.entityScriptContentAvailable diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp index 03d10887f8c..3f5125f913d 100644 --- a/libraries/script-engine/src/ScriptValueUtils.cpp +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -806,8 +806,7 @@ void animationDetailsFromScriptValue(const ScriptValuePointer& object, Animation } ScriptValuePointer meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in) { - return engine->newQObject(in, ScriptEngine::QtOwnership, - ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); + return engine->newQObject(in, ScriptEngine::QtOwnership); } void meshFromScriptValue(const ScriptValuePointer& value, MeshProxy*& out) { diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp index 142d2dbb2a8..db888c3e99d 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp @@ -1,6 +1,6 @@ // // ScriptContextQtAgent.cpp -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 5/22/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h index 15e02e99348..05f4254bf00 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h @@ -1,6 +1,6 @@ // // ScriptContextQtAgent.h -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 5/22/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp index 0e37545840a..41cd945ca27 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp @@ -1,6 +1,6 @@ // // ScriptContextQtWrapper.cpp -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 5/22/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h index 229a5b71025..b2f7726d85c 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h @@ -1,6 +1,6 @@ // // ScriptContextQtWrapper.h -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 5/22/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index 258a792165f..2552856727b 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -1,6 +1,6 @@ // // ScriptEngineQtScript.cpp -// libraries/script-engine-qtscript/src +// libraries/script-engine/src/qtscript // // Created by Brad Hefta-Gaub on 12/14/13. // Copyright 2013 High Fidelity, Inc. @@ -869,11 +869,11 @@ ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, return ScriptProgramPointer(new ScriptProgramQtWrapper(this, result)); } -ScriptValuePointer ScriptEngineQtScript::newQObject(QObject* obj, +ScriptValuePointer ScriptEngineQtScript::newQObject(QObject* object, ScriptEngine::ValueOwnership ownership, const ScriptEngine::QObjectWrapOptions& options) { - QScriptValue result = QScriptEngine::newQObject(obj, static_cast(ownership), - (QScriptEngine::QObjectWrapOptions)(int)options); + QScriptValue result = QScriptEngine::newQObject(object, static_cast(ownership), + (QScriptEngine::QObjectWrapOptions)((int)options | DEFAULT_QOBJECT_WRAP_OPTIONS)); return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); } diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index fa3d274d148..44712f99a52 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -1,6 +1,6 @@ // // ScriptEngineQtScript.h -// libraries/script-engine-qtscript/src +// libraries/script-engine/src/qtscript // // Created by Brad Hefta-Gaub on 12/14/13. // Copyright 2013 High Fidelity, Inc. diff --git a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp index be5f4df111a..11dba1417e5 100644 --- a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp @@ -1,6 +1,6 @@ // // ScriptProgramQtWrapper.cpp -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 8/24/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h index dca9c9d83a8..ddd477b90b9 100644 --- a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h @@ -1,6 +1,6 @@ // // ScriptProgramQtWrapper.h -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 5/21/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp index 755d2556db0..c56f021f88f 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp @@ -1,6 +1,6 @@ // // ScriptValueIteratorQtWrapper.cpp -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 8/29/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h index ee5d20ef1e1..7835e7cfae0 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h @@ -1,6 +1,6 @@ // // ScriptValueIteratorQtWrapper.h -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 8/29/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp index 0bdb8245496..f0d1e4d22bc 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp @@ -1,6 +1,6 @@ // // ScriptValueQtWrapper.cpp -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 5/16/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h index 5ac1dea9430..d7fa124a5aa 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h @@ -1,6 +1,6 @@ // // ScriptValueQtWrapper.h -// libraries/script-engine/src +// libraries/script-engine/src/qtscript // // Created by Heather Anderson on 5/16/21. // Copyright 2021 Vircadia contributors. diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 66a17509e3e..d7be1d3e618 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,8 +1,6 @@ set(TARGET_NAME ui) setup_hifi_library(OpenGL Multimedia Network Qml Quick WebChannel WebSockets XmlPatterns ${PLATFORM_QT_COMPONENTS}) link_hifi_libraries(shared networking qml gl audio audio-client plugins pointers script-engine) -include_hifi_library_headers(animation) -include_hifi_library_headers(entities) include_hifi_library_headers(controllers) # Required for some low level GL interaction in the OffscreenQMLSurface diff --git a/libraries/ui/src/ui/QmlWrapper.h b/libraries/ui/src/ui/QmlWrapper.h index b768f3c262d..b5150f440c6 100644 --- a/libraries/ui/src/ui/QmlWrapper.h +++ b/libraries/ui/src/ui/QmlWrapper.h @@ -36,7 +36,7 @@ ScriptValuePointer wrapperToScriptValue(ScriptEngine* engine, T* const &in) { if (!in) { return engine->undefinedValue(); } - return engine->newQObject(in, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); + return engine->newQObject(in, ScriptEngine::QtOwnership); } template diff --git a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp index 05b1804f87b..e23023e137a 100644 --- a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp +++ b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp @@ -20,7 +20,7 @@ ScriptValuePointer toolbarToScriptValue(ScriptEngine* engine, ToolbarProxy* cons if (!in) { return engine->undefinedValue(); } - return engine->newQObject(in, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); + return engine->newQObject(in, ScriptEngine::QtOwnership); } void toolbarFromScriptValue(const ScriptValuePointer& value, ToolbarProxy* &out) { @@ -31,7 +31,7 @@ ScriptValuePointer toolbarButtonToScriptValue(ScriptEngine* engine, ToolbarButto if (!in) { return engine->undefinedValue(); } - return engine->newQObject(in, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater | ScriptEngine::ExcludeChildObjects); + return engine->newQObject(in, ScriptEngine::QtOwnership); } void toolbarButtonFromScriptValue(const ScriptValuePointer& value, ToolbarButtonProxy* &out) { diff --git a/plugins/JSAPIExample/CMakeLists.txt b/plugins/JSAPIExample/CMakeLists.txt index 02301654c85..c8858ad2cbb 100644 --- a/plugins/JSAPIExample/CMakeLists.txt +++ b/plugins/JSAPIExample/CMakeLists.txt @@ -1,6 +1,4 @@ set(TARGET_NAME JSAPIExample) setup_hifi_client_server_plugin(scripting) link_hifi_libraries(shared plugins script-engine) -include_hifi_library_headers(animation) -include_hifi_library_headers(entities) include_hifi_library_headers(networking) diff --git a/plugins/JSAPIExample/src/JSAPIExample.cpp b/plugins/JSAPIExample/src/JSAPIExample.cpp index 500d2b22f90..d2cddcc3b1f 100644 --- a/plugins/JSAPIExample/src/JSAPIExample.cpp +++ b/plugins/JSAPIExample/src/JSAPIExample.cpp @@ -63,7 +63,7 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { } qCWarning(logger) << "registering w/ScriptInitializerMixin..." << scriptInit.data(); scriptInit->registerScriptInitializer([this](ScriptEngine* engine) { - auto value = engine->newQObject(this, ScriptEngine::QtOwnership, ScriptEngine::ExcludeDeleteLater); + auto value = engine->newQObject(this, ScriptEngine::QtOwnership); engine->globalObject()->setProperty(objectName(), value); // qCDebug(logger) << "setGlobalInstance" << objectName() << engine->property("fileName"); }); @@ -174,7 +174,7 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { raiseScriptingError(context(), "error creating scoped settings instance: " + error); return engine->nullValue(); } - return engine->newQObject(cppValue, ScriptEngine::ScriptOwnership, ScriptEngine::ExcludeDeleteLater); + return engine->newQObject(cppValue, ScriptEngine::ScriptOwnership); } private: From e799518e005ac2dd847530df69a8cc63c2e64509 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Tue, 31 Aug 2021 20:42:44 -0700 Subject: [PATCH 06/34] moving EntityItemID from script-engine to shared --- .../entities/src/EntityScriptingInterface.cpp | 7 +- libraries/script-engine/src/EntityItemID.cpp | 74 ------------------- libraries/script-engine/src/ScriptManager.cpp | 8 +- .../script-engine/src/ScriptValueUtils.cpp | 24 ++++++ .../script-engine/src/ScriptValueUtils.h | 5 ++ libraries/shared/src/EntityItemID.cpp | 42 +++++++++++ .../src/EntityItemID.h | 10 +-- 7 files changed, 80 insertions(+), 90 deletions(-) delete mode 100644 libraries/script-engine/src/EntityItemID.cpp create mode 100644 libraries/shared/src/EntityItemID.cpp rename libraries/{script-engine => shared}/src/EntityItemID.h (72%) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index ba338e6084d..f3723b17444 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -145,7 +145,7 @@ void EntityScriptingInterface::attachDefaultEventHandlers(ScriptManager* manager using SingleEntityHandler = std::function; auto makeSingleEntityHandler = [manager](QString eventName) -> SingleEntityHandler { return [manager, eventName](const EntityItemID& entityItemID) { - manager->forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(manager->engine().data()) }); + manager->forwardHandlerCall(entityItemID, eventName, { EntityItemIDtoScriptValue(manager->engine().data(), entityItemID) }); }; }; @@ -161,7 +161,7 @@ void EntityScriptingInterface::attachDefaultEventHandlers(ScriptManager* manager if (!EntityTree::areEntityClicksCaptured()) { ScriptEngine* engine = manager->engine().data(); manager->forwardHandlerCall(entityItemID, eventName, - { entityItemID.toScriptValue(engine), event.toScriptValue(engine) }); + { EntityItemIDtoScriptValue(engine, entityItemID), event.toScriptValue(engine) }); } }; }; @@ -178,7 +178,8 @@ void EntityScriptingInterface::attachDefaultEventHandlers(ScriptManager* manager return [manager, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { ScriptEngine* engine = manager->engine().data(); manager->forwardHandlerCall(idA, eventName, - { idA.toScriptValue(engine), idB.toScriptValue(engine), + { EntityItemIDtoScriptValue(engine, idA), + EntityItemIDtoScriptValue(engine, idB), collisionToScriptValue(engine, collision) }); }; }; diff --git a/libraries/script-engine/src/EntityItemID.cpp b/libraries/script-engine/src/EntityItemID.cpp deleted file mode 100644 index 275637dfa84..00000000000 --- a/libraries/script-engine/src/EntityItemID.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// EntityItemID.cpp -// libraries/script-engine/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "EntityItemID.h" -#include -#include - -#include -#include -#include - -#include -#include "ScriptValue.h" -#include "ScriptValueUtils.h" - -int entityItemIDTypeID = qRegisterMetaType(); - -EntityItemID::EntityItemID() : QUuid() -{ -} - - -EntityItemID::EntityItemID(const QUuid& id) : QUuid(id) -{ -} - -// EntityItemID::EntityItemID(const EntityItemID& other) : QUuid(other) -// { -// } - -EntityItemID EntityItemID::readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead) { - EntityItemID result; - if (bytesLeftToRead >= NUM_BYTES_RFC4122_UUID) { - BufferParser(data, bytesLeftToRead).readUuid(result); - } - return result; -} - -ScriptValuePointer EntityItemID::toScriptValue(ScriptEngine* engine) const { - return EntityItemIDtoScriptValue(engine, *this); -} - -ScriptValuePointer EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& id) { - return quuidToScriptValue(engine, id); -} - -void EntityItemIDfromScriptValue(const ScriptValuePointer &object, EntityItemID& id) { - quuidFromScriptValue(object, id); -} - -QVector qVectorEntityItemIDFromScriptValue(const ScriptValuePointer& array) { - if (!array->isArray()) { - return QVector(); - } - QVector newVector; - int length = array->property("length")->toInteger(); - newVector.reserve(length); - for (int i = 0; i < length; i++) { - QString uuidAsString = array->property(i)->toString(); - EntityItemID fromString(uuidAsString); - newVector << fromString; - } - return newVector; -} - -size_t std::hash::operator()(const EntityItemID& id) const { return qHash(id); } diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 5388f728592..cb2e88840c6 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -2340,7 +2340,7 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q auto scriptEngine = engine().data(); ScriptValueList args; - args << entityID.toScriptValue(scriptEngine); + args << EntityItemIDtoScriptValue(scriptEngine, entityID); args << scriptValueFromSequence(scriptEngine, params); ScriptValuePointer oldData = scriptEngine->globalObject()->property("Script")->property("remoteCallerID"); @@ -2383,7 +2383,7 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q auto scriptEngine = engine().data(); ScriptValueList args; - args << entityID.toScriptValue(scriptEngine); + args << EntityItemIDtoScriptValue(scriptEngine, entityID); args << event.toScriptValue(scriptEngine); callWithEnvironment(entityID, details.definingSandboxURL, entityScript->property(methodName), entityScript, args); } @@ -2423,8 +2423,8 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q auto scriptEngine = engine().data(); ScriptValueList args; - args << entityID.toScriptValue(scriptEngine); - args << otherID.toScriptValue(scriptEngine); + args << EntityItemIDtoScriptValue(scriptEngine, entityID); + args << EntityItemIDtoScriptValue(scriptEngine, otherID); args << collisionToScriptValue(scriptEngine, collision); callWithEnvironment(entityID, details.definingSandboxURL, entityScript->property(methodName), entityScript, args); } diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp index 3f5125f913d..4f52eb5572e 100644 --- a/libraries/script-engine/src/ScriptValueUtils.cpp +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "ScriptEngine.h" #include "ScriptEngineCast.h" @@ -885,3 +886,26 @@ void promiseFromScriptValue(const ScriptValuePointer& object, std::shared_ptr& promise) { return engine->newQObject(promise.get()); } + +ScriptValuePointer EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& id) { + return quuidToScriptValue(engine, id); +} + +void EntityItemIDfromScriptValue(const ScriptValuePointer &object, EntityItemID& id) { + quuidFromScriptValue(object, id); +} + +QVector qVectorEntityItemIDFromScriptValue(const ScriptValuePointer& array) { + if (!array->isArray()) { + return QVector(); + } + QVector newVector; + int length = array->property("length")->toInteger(); + newVector.reserve(length); + for (int i = 0; i < length; i++) { + QString uuidAsString = array->property(i)->toString(); + EntityItemID fromString(uuidAsString); + newVector << fromString; + } + return newVector; +} diff --git a/libraries/script-engine/src/ScriptValueUtils.h b/libraries/script-engine/src/ScriptValueUtils.h index c65561ff7af..8d0919ee5b2 100644 --- a/libraries/script-engine/src/ScriptValueUtils.h +++ b/libraries/script-engine/src/ScriptValueUtils.h @@ -262,6 +262,11 @@ class MiniPromise; void promiseFromScriptValue(const ScriptValuePointer& object, std::shared_ptr& promise); ScriptValuePointer promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise); +class EntityItemID; +ScriptValuePointer EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& properties); +void EntityItemIDfromScriptValue(const ScriptValuePointer& object, EntityItemID& properties); +QVector qVectorEntityItemIDFromScriptValue(const ScriptValuePointer& array); + #endif // #define hifi_ScriptValueUtils_h /// @} diff --git a/libraries/shared/src/EntityItemID.cpp b/libraries/shared/src/EntityItemID.cpp new file mode 100644 index 00000000000..8cb34c13db8 --- /dev/null +++ b/libraries/shared/src/EntityItemID.cpp @@ -0,0 +1,42 @@ +// +// EntityItemID.cpp +// libraries/shared/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "EntityItemID.h" +#include +#include + +#include "BufferParser.h" +#include "UUID.h" + +int entityItemIDTypeID = qRegisterMetaType(); + +EntityItemID::EntityItemID() : QUuid() +{ +} + + +EntityItemID::EntityItemID(const QUuid& id) : QUuid(id) +{ +} + +// EntityItemID::EntityItemID(const EntityItemID& other) : QUuid(other) +// { +// } + +EntityItemID EntityItemID::readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead) { + EntityItemID result; + if (bytesLeftToRead >= NUM_BYTES_RFC4122_UUID) { + BufferParser(data, bytesLeftToRead).readUuid(result); + } + return result; +} + +size_t std::hash::operator()(const EntityItemID& id) const { return qHash(id); } diff --git a/libraries/script-engine/src/EntityItemID.h b/libraries/shared/src/EntityItemID.h similarity index 72% rename from libraries/script-engine/src/EntityItemID.h rename to libraries/shared/src/EntityItemID.h index 72a1bc90c73..51ea1871ae3 100644 --- a/libraries/script-engine/src/EntityItemID.h +++ b/libraries/shared/src/EntityItemID.h @@ -1,6 +1,6 @@ // // EntityItemID.h -// libraries/script-engine/src +// libraries/shared/src // // Created by Brad Hefta-Gaub on 12/4/13. // Copyright 2013 High Fidelity, Inc. @@ -20,10 +20,6 @@ #include #include -class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; - const QUuid UNKNOWN_ENTITY_ID; // null uuid /// Abstract ID for editing model items. Used in EntityItem JS API. @@ -33,7 +29,6 @@ class EntityItemID : public QUuid { EntityItemID(const QUuid& id); // EntityItemID(const EntityItemID& other); static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead); - ScriptValuePointer toScriptValue(ScriptEngine* engine) const; bool isInvalidID() const { return *this == UNKNOWN_ENTITY_ID; } }; @@ -45,9 +40,6 @@ inline QDebug operator<<(QDebug debug, const EntityItemID& id) { Q_DECLARE_METATYPE(EntityItemID); Q_DECLARE_METATYPE(QVector); -ScriptValuePointer EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& properties); -void EntityItemIDfromScriptValue(const ScriptValuePointer &object, EntityItemID& properties); -QVector qVectorEntityItemIDFromScriptValue(const ScriptValuePointer& array); // Allow the use of std::unordered_map with QUuid keys namespace std { template<> struct hash { size_t operator()(const EntityItemID& id) const; }; } From 8db1cfe22406ceee2d7dc59718cefade0bdc11c6 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Tue, 31 Aug 2021 20:43:22 -0700 Subject: [PATCH 07/34] dropping dependencies from networking to script-engine by moving EntityScriptClient and LocationScriptingInterface --- libraries/networking/CMakeLists.txt | 1 - .../src/EntityScriptClient.cpp | 4 ++-- .../src/EntityScriptClient.h | 10 +++++----- .../src/LocationScriptingInterface.cpp | 10 +++++----- .../src/LocationScriptingInterface.h | 2 +- plugins/hifiSdl2/CMakeLists.txt | 1 - 6 files changed, 13 insertions(+), 15 deletions(-) rename libraries/{networking => script-engine}/src/EntityScriptClient.cpp (99%) rename libraries/{networking => script-engine}/src/EntityScriptClient.h (94%) rename libraries/{networking => script-engine}/src/LocationScriptingInterface.cpp (89%) rename libraries/{networking => script-engine}/src/LocationScriptingInterface.h (96%) diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 09b0e182de2..9f63f2cb00f 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -1,7 +1,6 @@ set(TARGET_NAME networking) setup_hifi_library(Network) link_hifi_libraries(shared platform) -include_hifi_library_headers(script-engine) target_openssl() target_tbb() diff --git a/libraries/networking/src/EntityScriptClient.cpp b/libraries/script-engine/src/EntityScriptClient.cpp similarity index 99% rename from libraries/networking/src/EntityScriptClient.cpp rename to libraries/script-engine/src/EntityScriptClient.cpp index fb98e8042bb..93406da9531 100644 --- a/libraries/networking/src/EntityScriptClient.cpp +++ b/libraries/script-engine/src/EntityScriptClient.cpp @@ -1,6 +1,6 @@ #include "EntityScriptClient.h" -#include "NodeList.h" -#include "NetworkLogging.h" +#include +#include #include "EntityScriptUtils.h" #include diff --git a/libraries/networking/src/EntityScriptClient.h b/libraries/script-engine/src/EntityScriptClient.h similarity index 94% rename from libraries/networking/src/EntityScriptClient.h rename to libraries/script-engine/src/EntityScriptClient.h index 4cfb03dca7e..b493c29d525 100644 --- a/libraries/networking/src/EntityScriptClient.h +++ b/libraries/script-engine/src/EntityScriptClient.h @@ -1,6 +1,6 @@ // // EntityScriptClient.h -// libraries/networking/src +// libraries/script-engine/src // // Created by Ryan Huffman on 2017/01/13 // Copyright 2017 High Fidelity, Inc. @@ -12,10 +12,10 @@ #ifndef hifi_EntityScriptClient_h #define hifi_EntityScriptClient_h -#include "ClientServerUtils.h" -#include "LimitedNodeList.h" -#include "ReceivedMessage.h" -#include "AssetUtils.h" +#include +#include +#include +#include #include "EntityScriptUtils.h" #include diff --git a/libraries/networking/src/LocationScriptingInterface.cpp b/libraries/script-engine/src/LocationScriptingInterface.cpp similarity index 89% rename from libraries/networking/src/LocationScriptingInterface.cpp rename to libraries/script-engine/src/LocationScriptingInterface.cpp index 23884cab1e3..466ac779dab 100644 --- a/libraries/networking/src/LocationScriptingInterface.cpp +++ b/libraries/script-engine/src/LocationScriptingInterface.cpp @@ -1,6 +1,6 @@ // // LocationScriptingInterface.cpp -// libraries/networking/src +// libraries/script-engine/src // // Created by Ryan Huffman on 4/29/14. // Copyright 2014 High Fidelity, Inc. @@ -11,10 +11,10 @@ #include "LocationScriptingInterface.h" -#include "AddressManager.h" -#include -#include -#include +#include +#include "ScriptContext.h" +#include "ScriptEngine.h" +#include "ScriptValue.h" LocationScriptingInterface* LocationScriptingInterface::getInstance() { static LocationScriptingInterface sharedInstance; diff --git a/libraries/networking/src/LocationScriptingInterface.h b/libraries/script-engine/src/LocationScriptingInterface.h similarity index 96% rename from libraries/networking/src/LocationScriptingInterface.h rename to libraries/script-engine/src/LocationScriptingInterface.h index 0fc6b6ec724..7603e113fa4 100644 --- a/libraries/networking/src/LocationScriptingInterface.h +++ b/libraries/script-engine/src/LocationScriptingInterface.h @@ -1,6 +1,6 @@ // // LocationScriptingInterface.h -// libraries/networking/src +// libraries/script-engine/src // // Created by Ryan Huffman on 4/29/14. // Copyright 2014 High Fidelity, Inc. diff --git a/plugins/hifiSdl2/CMakeLists.txt b/plugins/hifiSdl2/CMakeLists.txt index 16ce6f51b4a..47d382681fd 100644 --- a/plugins/hifiSdl2/CMakeLists.txt +++ b/plugins/hifiSdl2/CMakeLists.txt @@ -17,6 +17,5 @@ if (NOT APPLE) endif() setup_hifi_plugin(Qml) link_hifi_libraries(shared controllers ui plugins input-plugins) - include_hifi_library_headers(script-engine) target_sdl2() endif() From d8546da73042291463c84e7ee5012f3a5df992b1 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Tue, 31 Aug 2021 21:28:06 -0700 Subject: [PATCH 08/34] added custom type support --- .../src/qtscript/ScriptEngineQtScript.cpp | 59 ++++++++++++++++--- .../src/qtscript/ScriptEngineQtScript.h | 13 +++- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index 2552856727b..fe3cc76c88e 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -1013,25 +1013,70 @@ bool ScriptEngineQtScript::raiseException(const ScriptValuePointer& exception) { } ScriptValuePointer ScriptEngineQtScript::create(int type, const void* ptr) { + // first we'll try custom types registered with us + ScriptEngine::MarshalFunction marshalFunc = nullptr; + ScriptValuePointer prototype; + { + std::lock_guard guard(_customTypeProtect); + TCustomTypeMap::const_iterator loc = _customTypes.find(type); + if (loc != _customTypes.end()) { + const CustomTypeInfo& typeInfo = loc->second; + marshalFunc = typeInfo.marshalFunc; + prototype = typeInfo.prototype; + } + } + if (marshalFunc) { + ScriptValuePointer result = marshalFunc(this, ptr); + if (result && prototype) { + result->setPrototype(prototype); + } + return result; + } + + // falling back to having QtScript handle it QScriptValue result = qScriptValueFromValue_helper(this, type, ptr); return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); } bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, void* ptr) { + // first we'll try custom types registered with us + ScriptEngine::DemarshalFunction demarshalFunc = nullptr; + { + std::lock_guard guard(_customTypeProtect); + TCustomTypeMap::const_iterator loc = _customTypes.find(type); + if (loc != _customTypes.end()) { + demarshalFunc = loc->second.demarshalFunc; + } + } + if (demarshalFunc) { + demarshalFunc(value, ptr); + return true; + } + + // falling back to having QtScript handle it ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); if (unwrapped == nullptr) { return false; } return qscriptvalue_cast_helper(unwrapped->toQtValue(), type, ptr); } -/* + void ScriptEngineQtScript::registerCustomType(int type, - ScriptEngine::MarshalFunction mf, - ScriptEngine::DemarshalFunction df, - const ScriptValuePointer& prototype) { + ScriptEngine::MarshalFunction marshalFunc, + ScriptEngine::DemarshalFunction demarshalFunc, + const ScriptValuePointer& prototype) +{ ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(prototype); - if (unwrapped != nullptr) { - qScriptRegisterMetaType_helper(this, type, mf, df, unwrapped->toQtValue()); + if (unwrapped == nullptr) { + return; + } + + std::lock_guard guard(_customTypeProtect); + TCustomTypeMap::iterator loc = _customTypes.find(type); + if(loc == _customTypes.end()) { + _customTypes.insert(TCustomTypeMap::value_type(type, CustomTypeInfo())).first; } + CustomTypeInfo& typeInfo = loc->second; + typeInfo.marshalFunc = marshalFunc; + typeInfo.demarshalFunc = demarshalFunc; } -*/ diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 44712f99a52..0055062bc4b 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -382,7 +382,8 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q public: // not for public use, but I don't like how Qt strings this along with private friend functions virtual ScriptValuePointer create(int type, const void* ptr); virtual bool convert(const ScriptValuePointer& value, int type, void* ptr); - virtual void registerCustomType(int type, ScriptEngine::MarshalFunction mf, ScriptEngine::DemarshalFunction df, const ScriptValuePointer& prototype); + virtual void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, + ScriptEngine::DemarshalFunction demarshalFunc, const ScriptValuePointer& prototype); protected: // like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues @@ -403,6 +404,16 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q */ Q_INVOKABLE void executeOnScriptThread(std::function function, const Qt::ConnectionType& type = Qt::QueuedConnection ); + // store for handling custom type marshaling/demarshaling + struct CustomTypeInfo { + ScriptEngine::MarshalFunction marshalFunc; + ScriptEngine::DemarshalFunction demarshalFunc; + ScriptValuePointer prototype; + }; + typedef std::map TCustomTypeMap; + TCustomTypeMap _customTypes; + std::mutex _customTypeProtect; + QPointer _manager; ScriptValuePointer _nullValue; From e5be895b0396f173796e3f986bbdff9a87d3a3a4 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Wed, 1 Sep 2021 18:25:58 -0700 Subject: [PATCH 09/34] early smoketesting --- interface/src/avatar/MyAvatar.cpp | 3 +- interface/src/ui/InteractiveWindow.cpp | 6 +- interface/src/ui/JSConsole.cpp | 4 +- libraries/animation/src/AnimVariant.cpp | 18 +- libraries/animation/src/Rig.cpp | 4 +- libraries/audio/src/AudioEffectOptions.cpp | 2 +- libraries/audio/src/AudioInjectorOptions.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 4 +- libraries/script-engine/src/ScriptEngine.h | 1 + .../script-engine/src/ScriptEngineCast.h | 3 +- libraries/script-engine/src/ScriptManager.cpp | 25 +-- .../src/qtscript/ScriptContextQtWrapper.cpp | 2 +- .../src/qtscript/ScriptEngineQtScript.cpp | 155 ++++++++++++------ .../src/qtscript/ScriptEngineQtScript.h | 12 +- 14 files changed, 150 insertions(+), 91 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9732f78948b..af3efb4b848 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2670,8 +2670,7 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() { EntityItemProperties entityProperties = entity->getProperties(desiredProperties); { std::lock_guard guard(_scriptEngineLock); - ScriptValuePointer scriptProperties; - scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties); + ScriptValuePointer scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties); avatarEntityData["properties"] = scriptProperties->toVariant(); } avatarEntitiesData.append(QVariant(avatarEntityData)); diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 2f49bc9615f..e86b6676963 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -102,8 +102,10 @@ ScriptValuePointer interactiveWindowPointerToScriptValue(ScriptEngine* engine, c } void interactiveWindowPointerFromScriptValue(const ScriptValuePointer& object, InteractiveWindowPointer& out) { - if (const auto interactiveWindow = qobject_cast(object->toQObject())) { - out = interactiveWindow; + if (!object) { + if (const auto interactiveWindow = qobject_cast(object->toQObject())) { + out = interactiveWindow; + } } } diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index cdb819ecb7e..de352598168 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -375,10 +375,10 @@ void JSConsole::commandFinished() { _ui->promptTextEdit->setFocus(); } - bool error = (_scriptManager->engine()->hasUncaughtException() || result->isError()); + bool error = (_scriptManager->engine()->hasUncaughtException() || (result && result->isError())); QString gutter = error ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND; QString resultColor = error ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE; - QString resultStr = "" + result->toString().toHtmlEscaped() + ""; + QString resultStr = result ? "" + result->toString().toHtmlEscaped() + "" : ""; appendMessage(gutter, resultStr); resetCurrentCommandHistory(); diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index 9b596b2356b..db877bf91a8 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -89,11 +89,11 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou while (property->hasNext()) { property->next(); ScriptValuePointer value = property->value(); - if (value->isBool()) { + if (value && value->isBool()) { set(property->name(), value->toBool()); - } else if (value->isString()) { + } else if (value && value->isString()) { set(property->name(), value->toString()); - } else if (value->isNumber()) { + } else if (value && value->isNumber()) { int asInteger = value->toInt32(); float asFloat = value->toNumber(); if (asInteger == asFloat) { @@ -102,15 +102,15 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou set(property->name(), asFloat); } } else { // Try to get x,y,z and possibly w - if (value->isObject()) { + if (value && value->isObject()) { ScriptValuePointer x = value->property("x"); - if (x->isNumber()) { + if (x && x->isNumber()) { ScriptValuePointer y = value->property("y"); - if (y->isNumber()) { + if (y && y->isNumber()) { ScriptValuePointer z = value->property("z"); - if (z->isNumber()) { + if (z && z->isNumber()) { ScriptValuePointer w = value->property("w"); - if (w->isNumber()) { + if (w && w->isNumber()) { set(property->name(), glm::quat(w->toNumber(), x->toNumber(), y->toNumber(), z->toNumber())); } else { set(property->name(), glm::vec3(x->toNumber(), y->toNumber(), z->toNumber())); @@ -120,7 +120,7 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou } } } - qCWarning(animation) << "Ignoring unrecognized data" << value->toString() << "for animation property" << property->name(); + qCWarning(animation) << "Ignoring unrecognized data " << (value ? value->toString() : "(undefined)") << " for animation property " << property->name(); Q_ASSERT(false); } } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 9cc06847b05..409df3f4d64 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1589,7 +1589,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList) { // called in script thread // validate argument types - if (handler->isFunction() && (isListOfStrings(propertiesList) || propertiesList->isUndefined() || propertiesList->isNull())) { + if (handler && handler->isFunction() && (isListOfStrings(propertiesList) || propertiesList->isUndefined() || propertiesList->isNull())) { QMutexLocker locker(&_stateMutex); // Find a safe id, even if there are lots of many scripts add and remove handlers repeatedly. while (!_nextStateHandlerId || _stateHandlers.contains(_nextStateHandlerId)) { // 0 is unused, and don't reuse existing after wrap. @@ -1610,7 +1610,7 @@ ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, Scr void Rig::removeAnimationStateHandler(ScriptValuePointer identifier) { // called in script thread // validate arguments - if (identifier->isNumber()) { + if (identifier && identifier->isNumber()) { QMutexLocker locker(&_stateMutex); _stateHandlers.remove(identifier->toInt32()); // silently continues if handler not present. 0 is unused } else { diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index dc7dd38b23a..4fb7d939838 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -67,7 +67,7 @@ static const float LATE_MIX_RIGHT_DEFAULT = 90.0f; static const float WET_DRY_MIX_DEFAULT = 50.0f; static void setOption(ScriptValuePointer arguments, const QString name, float defaultValue, float& variable) { - variable = arguments->property(name)->isNumber() ? (float)arguments->property(name)->toNumber() : defaultValue; + variable = arguments && arguments->property(name)->isNumber() ? (float)arguments->property(name)->toNumber() : defaultValue; } /*@jsdoc diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index b49adf6963d..27ca80687fa 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -67,7 +67,7 @@ ScriptValuePointer injectorOptionsToScriptValue(ScriptEngine* engine, const Audi * removed.

*/ void injectorOptionsFromScriptValue(const ScriptValuePointer& object, AudioInjectorOptions& injectorOptions) { - if (!object->isObject()) { + if (!object || !object->isObject()) { qWarning() << "Audio injector options is not an object."; return; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index fa967cfcdf0..1342c89fb60 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -3178,11 +3178,11 @@ void RayToAvatarIntersectionResultFromScriptValue(const ScriptValuePointer& obje value.face = boxFaceFromString(object->property("face")->toVariant().toString()); ScriptValuePointer intersection = object->property("intersection"); - if (intersection->isValid()) { + if (intersection && intersection->isValid()) { vec3FromScriptValue(intersection, value.intersection); } ScriptValuePointer surfaceNormal = object->property("surfaceNormal"); - if (surfaceNormal->isValid()) { + if (surfaceNormal && surfaceNormal->isValid()) { vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } value.jointIndex = object->property("jointIndex")->toInt32(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8488873680b..34b1846d7e6 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -103,6 +103,7 @@ class ScriptEngine { virtual bool setProperty(const char* name, const QVariant& value) = 0; virtual void setProcessEventsInterval(int interval) = 0; virtual QThread* thread() const = 0; + virtual void setThread(QThread* thread) = 0; virtual ScriptValuePointer undefinedValue() = 0; virtual ScriptValuePointer uncaughtException() const = 0; virtual QStringList uncaughtExceptionBacktrace() const = 0; diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h index 22221e74a4c..d597efc7806 100644 --- a/libraries/script-engine/src/ScriptEngineCast.h +++ b/libraries/script-engine/src/ScriptEngineCast.h @@ -65,7 +65,8 @@ int scriptRegisterMetaType(ScriptEngine* eng, ScriptValuePointer (*toScriptValue)(ScriptEngine*, const T& t), void (*fromScriptValue)(const ScriptValuePointer&, T& t), const ScriptValuePointer& prototype = ScriptValuePointer(), - T* = 0) { + T* = 0) +{ const int id = qRegisterMetaType(); // make sure it's registered eng->registerCustomType(id, reinterpret_cast(toScriptValue), reinterpret_cast(fromScriptValue), prototype); diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index cb2e88840c6..06735094780 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -87,6 +87,8 @@ int scriptManagerPointerMetaID = qRegisterMetaType(); Q_DECLARE_METATYPE(ExternalResource::Bucket); +Q_DECLARE_METATYPE(ScriptValuePointer); + // --- Static script initialization registry static ScriptManager::StaticInitializerNode* rootInitializer = nullptr; @@ -325,6 +327,7 @@ void ScriptManager::runInThread() { QThread* workerThread = new QThread(); QString name = QString("js:") + getFilename().replace("about:",""); workerThread->setObjectName(name); + _engine->setThread(workerThread); moveToThread(workerThread); // NOTE: If you connect any essential signals for proper shutdown or cleanup of @@ -1256,13 +1259,13 @@ ScriptValuePointer ScriptManager::currentModule() { } auto jsRequire = _engine->globalObject()->property("Script")->property("require"); auto cache = jsRequire->property("cache"); - auto candidate = ScriptValuePointer(); + ScriptValuePointer candidate; ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan - for (auto context = _engine->currentContext(); context && !candidate->isObject(); parentContext = context->parentContext(), context = parentContext.data()) { + for (auto context = _engine->currentContext(); context && (!candidate || !candidate->isObject()); parentContext = context->parentContext(), context = parentContext.data()) { auto contextInfo = context->functionContext(); candidate = cache->property(contextInfo->fileName()); } - if (!candidate->isObject()) { + if (!candidate || !candidate->isObject()) { return ScriptValuePointer(); } return candidate; @@ -1589,8 +1592,8 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer } _parentURL = parentURL; - if (callback->isFunction()) { - callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, ScriptValuePointer(callback), ScriptValuePointer(), ScriptValueList()); + if (callback && callback->isFunction()) { + callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, callback, ScriptValuePointer(), ScriptValueList()); } loader->deleteLater(); @@ -1603,7 +1606,7 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer loader->start(processLevelMaxRetries); - if (!callback->isFunction() && !loader->isFinished()) { + if ((!callback || !callback->isFunction()) && !loader->isFinished()) { QEventLoop loop; QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit); loop.exec(); @@ -1963,7 +1966,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c if (sandbox->hasUncaughtException()) { exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); sandbox->clearExceptions(); - } else if (testConstructor->isError()) { + } else if (testConstructor && testConstructor->isError()) { exception = testConstructor; } } else { @@ -2038,7 +2041,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c if (sandbox->hasUncaughtException()) { exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); sandbox->clearExceptions(); - } else if (testConstructor->isError()) { + } else if (testConstructor && testConstructor->isError()) { exception = testConstructor; } } @@ -2048,7 +2051,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c // exception = makeError("UNSAFE_ENTITY_SCRIPTS == 0"); } - if (exception->isError()) { + if (exception && exception->isError()) { // create a local copy using makeError to decouple from the sandbox engine exception = _engine->makeError(exception); setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); @@ -2057,7 +2060,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c } // CONSTRUCTOR VIABILITY - if (!testConstructor->isFunction()) { + if (!testConstructor || !testConstructor->isFunction()) { QString testConstructorType = QString(testConstructor->toVariant().typeName()); if (testConstructorType == "") { testConstructorType = "empty"; @@ -2100,7 +2103,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c doWithEnvironment(entityID, sandboxURL, initialization); - if (entityScriptObject->isError()) { + if (entityScriptObject && entityScriptObject->isError()) { auto exception = entityScriptObject; setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); emit unhandledException(exception); diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp index 41cd945ca27..798d93a0eae 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp @@ -52,7 +52,7 @@ ScriptFunctionContextPointer ScriptContextQtWrapper::functionContext() const { ScriptContextPointer ScriptContextQtWrapper::parentContext() const { QScriptContext* result = _context->parentContext(); - return ScriptContextPointer(new ScriptContextQtWrapper(_engine, result)); + return result ? ScriptContextPointer(new ScriptContextQtWrapper(_engine, result)) : ScriptContextPointer(); } ScriptValuePointer ScriptContextQtWrapper::thisObject() const { diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index fe3cc76c88e..7700d778d2c 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -62,13 +62,16 @@ static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_P static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; +Q_DECLARE_METATYPE(ScriptValuePointer); + Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) int qfunctionSignatureMetaID = qRegisterMetaType(); int scriptEnginePointerMetaID = qRegisterMetaType(); bool ScriptEngineQtScript::IS_THREADSAFE_INVOCATION(const QThread* thread, const QString& method) { - if (QThread::currentThread() == thread) { + const QThread* currentThread = QThread::currentThread(); + if (currentThread == thread) { return true; } qCCritical(scriptengine) << QString("Scripting::%1 @ %2 -- ignoring thread-unsafe call from %3") @@ -380,11 +383,22 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { return QScriptValue(); } +static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValuePointer& src) { + return ScriptValueQtWrapper::fullUnwrap(static_cast(engine), src); +} + +static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValuePointer& dest) { + ScriptEngineQtScript* engine = static_cast(src.engine()); + dest = ScriptValuePointer(new ScriptValueQtWrapper(engine, src)); +} + ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : QScriptEngine(), _manager(scriptManager), _arrayBufferClass(new ArrayBufferClass(this)) { + qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue); + if (_manager) { connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { if (hasUncaughtException()) { @@ -397,6 +411,7 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : emit _manager->unhandledException(ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(thrown)))); } }, Qt::DirectConnection); + moveToThread(scriptManager->thread()); } QScriptValue null = QScriptEngine::nullValue(); @@ -993,6 +1008,10 @@ QThread* ScriptEngineQtScript::thread() const { return QScriptEngine::thread(); } +void ScriptEngineQtScript::setThread(QThread* thread) { + moveToThread(thread); +} + ScriptValuePointer ScriptEngineQtScript::uncaughtException() const { QScriptValue result = QScriptEngine::uncaughtException(); return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); @@ -1013,47 +1032,11 @@ bool ScriptEngineQtScript::raiseException(const ScriptValuePointer& exception) { } ScriptValuePointer ScriptEngineQtScript::create(int type, const void* ptr) { - // first we'll try custom types registered with us - ScriptEngine::MarshalFunction marshalFunc = nullptr; - ScriptValuePointer prototype; - { - std::lock_guard guard(_customTypeProtect); - TCustomTypeMap::const_iterator loc = _customTypes.find(type); - if (loc != _customTypes.end()) { - const CustomTypeInfo& typeInfo = loc->second; - marshalFunc = typeInfo.marshalFunc; - prototype = typeInfo.prototype; - } - } - if (marshalFunc) { - ScriptValuePointer result = marshalFunc(this, ptr); - if (result && prototype) { - result->setPrototype(prototype); - } - return result; - } - - // falling back to having QtScript handle it QScriptValue result = qScriptValueFromValue_helper(this, type, ptr); return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); } bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, void* ptr) { - // first we'll try custom types registered with us - ScriptEngine::DemarshalFunction demarshalFunc = nullptr; - { - std::lock_guard guard(_customTypeProtect); - TCustomTypeMap::const_iterator loc = _customTypes.find(type); - if (loc != _customTypes.end()) { - demarshalFunc = loc->second.demarshalFunc; - } - } - if (demarshalFunc) { - demarshalFunc(value, ptr); - return true; - } - - // falling back to having QtScript handle it ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); if (unwrapped == nullptr) { return false; @@ -1061,22 +1044,100 @@ bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, vo return qscriptvalue_cast_helper(unwrapped->toQtValue(), type, ptr); } +template +class CustomTypeInstance { +public: + static ScriptEngine::MarshalFunction marshalFunc; + static ScriptEngine::DemarshalFunction demarshalFunc; + + static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) { + ScriptEngineQtScript* unwrappedEngine = static_cast(engine); + ScriptValuePointer dest = marshalFunc(unwrappedEngine, src); + return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest); + } + + static void internalDemarshalFunc(const QScriptValue& src, void* dest) { + ScriptEngineQtScript* unwrappedEngine = static_cast(src.engine()); + ScriptValuePointer wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src)); + demarshalFunc(wrappedSrc, dest); + } +}; +template +ScriptEngine::MarshalFunction CustomTypeInstance::marshalFunc; +template +ScriptEngine::DemarshalFunction CustomTypeInstance::demarshalFunc; + +// I would *LOVE* it if there was a different way to do this, jeez! +// Qt requires two functions that have no parameters that give any context, +// one of the must return a QScriptValue (so we can't void* them into generics and stick them in the templates). +// This *has* to be done via templates but the whole point of this is to avoid leaking types into the rest of +// the system that would require anyone other than us to have a dependency on QtScript +#define CUSTOM_TYPE_ENTRY(idx) \ + case idx: \ + CustomTypeInstance::marshalFunc = marshalFunc; \ + CustomTypeInstance::demarshalFunc = demarshalFunc; \ + internalMarshalFunc = CustomTypeInstance::internalMarshalFunc; \ + internalDemarshalFunc = CustomTypeInstance::internalDemarshalFunc; \ + break; +#define CUSTOM_TYPE_ENTRY_10(idx) \ + CUSTOM_TYPE_ENTRY((idx * 10)); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 1); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 2); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 3); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 4); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 5); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 6); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 7); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 8); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 9); + void ScriptEngineQtScript::registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, ScriptEngine::DemarshalFunction demarshalFunc, const ScriptValuePointer& prototype) { - ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(prototype); - if (unwrapped == nullptr) { + QScriptValue unwrapped = ScriptValueQtWrapper::fullUnwrap(this, prototype); + QScriptEngine::MarshalFunction internalMarshalFunc; + QScriptEngine::DemarshalFunction internalDemarshalFunc; + + if (_nextCustomType >= 300) { // have we ran out of translators? + Q_ASSERT(false); return; } - std::lock_guard guard(_customTypeProtect); - TCustomTypeMap::iterator loc = _customTypes.find(type); - if(loc == _customTypes.end()) { - _customTypes.insert(TCustomTypeMap::value_type(type, CustomTypeInfo())).first; - } - CustomTypeInfo& typeInfo = loc->second; - typeInfo.marshalFunc = marshalFunc; - typeInfo.demarshalFunc = demarshalFunc; + switch (_nextCustomType++) { + CUSTOM_TYPE_ENTRY_10(0); + CUSTOM_TYPE_ENTRY_10(1); + CUSTOM_TYPE_ENTRY_10(2); + CUSTOM_TYPE_ENTRY_10(3); + CUSTOM_TYPE_ENTRY_10(4); + CUSTOM_TYPE_ENTRY_10(5); + CUSTOM_TYPE_ENTRY_10(6); + CUSTOM_TYPE_ENTRY_10(7); + CUSTOM_TYPE_ENTRY_10(8); + CUSTOM_TYPE_ENTRY_10(9); + CUSTOM_TYPE_ENTRY_10(10); + CUSTOM_TYPE_ENTRY_10(11); + CUSTOM_TYPE_ENTRY_10(12); + CUSTOM_TYPE_ENTRY_10(13); + CUSTOM_TYPE_ENTRY_10(14); + CUSTOM_TYPE_ENTRY_10(15); + CUSTOM_TYPE_ENTRY_10(16); + CUSTOM_TYPE_ENTRY_10(17); + CUSTOM_TYPE_ENTRY_10(18); + CUSTOM_TYPE_ENTRY_10(19); + CUSTOM_TYPE_ENTRY_10(20); + CUSTOM_TYPE_ENTRY_10(21); + CUSTOM_TYPE_ENTRY_10(22); + CUSTOM_TYPE_ENTRY_10(23); + CUSTOM_TYPE_ENTRY_10(24); + CUSTOM_TYPE_ENTRY_10(25); + CUSTOM_TYPE_ENTRY_10(26); + CUSTOM_TYPE_ENTRY_10(27); + CUSTOM_TYPE_ENTRY_10(28); + CUSTOM_TYPE_ENTRY_10(29); + CUSTOM_TYPE_ENTRY_10(30); + } + + qScriptRegisterMetaType_helper(this, type, internalMarshalFunc, internalDemarshalFunc, unwrapped); } diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 0055062bc4b..af127988a0a 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -89,6 +89,7 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q virtual bool setProperty(const char* name, const QVariant& value); virtual void setProcessEventsInterval(int interval); virtual QThread* thread() const; + virtual void setThread(QThread* thread); virtual ScriptValuePointer undefinedValue(); virtual ScriptValuePointer uncaughtException() const; virtual QStringList uncaughtExceptionBacktrace() const; @@ -404,18 +405,9 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q */ Q_INVOKABLE void executeOnScriptThread(std::function function, const Qt::ConnectionType& type = Qt::QueuedConnection ); - // store for handling custom type marshaling/demarshaling - struct CustomTypeInfo { - ScriptEngine::MarshalFunction marshalFunc; - ScriptEngine::DemarshalFunction demarshalFunc; - ScriptValuePointer prototype; - }; - typedef std::map TCustomTypeMap; - TCustomTypeMap _customTypes; - std::mutex _customTypeProtect; - QPointer _manager; + int _nextCustomType = 0; ScriptValuePointer _nullValue; ScriptValuePointer _undefinedValue; mutable ScriptContextQtPointer _currContext; From 6462ac106af033b23ce0e9ef6cd701fcb808d56e Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Fri, 3 Sep 2021 01:09:00 -0700 Subject: [PATCH 10/34] rework ScriptValue to act like a stack variable rather than a pointer --- assignment-client/src/Agent.cpp | 4 +- .../src/scripts/EntityScriptServer.cpp | 2 +- interface/src/AvatarBookmarks.cpp | 6 +- interface/src/LODManager.cpp | 6 +- interface/src/LODManager.h | 8 +- interface/src/avatar/AvatarManager.cpp | 10 +- interface/src/avatar/AvatarManager.h | 10 +- interface/src/avatar/MyAvatar.cpp | 26 +- interface/src/avatar/MyAvatar.h | 15 +- .../LaserPointerScriptingInterface.cpp | 4 +- .../raypick/LaserPointerScriptingInterface.h | 6 +- .../src/raypick/PickScriptingInterface.cpp | 16 +- .../src/raypick/PickScriptingInterface.h | 6 +- .../src/raypick/PointerScriptingInterface.cpp | 4 +- .../src/raypick/PointerScriptingInterface.h | 6 +- .../src/raypick/RayPickScriptingInterface.cpp | 4 +- .../src/raypick/RayPickScriptingInterface.h | 6 +- .../AccountServicesScriptingInterface.cpp | 18 +- .../AccountServicesScriptingInterface.h | 8 +- .../src/scripting/HMDScriptingInterface.cpp | 4 +- .../src/scripting/HMDScriptingInterface.h | 8 +- .../src/scripting/TestScriptingInterface.cpp | 4 +- .../src/scripting/TestScriptingInterface.h | 7 +- .../scripting/WindowScriptingInterface.cpp | 30 +- .../src/scripting/WindowScriptingInterface.h | 19 +- interface/src/ui/InteractiveWindow.cpp | 10 +- interface/src/ui/InteractiveWindow.h | 8 +- interface/src/ui/JSConsole.cpp | 14 +- interface/src/ui/JSConsole.h | 5 +- interface/src/ui/overlays/Overlays.cpp | 54 +- interface/src/ui/overlays/Overlays.h | 12 +- libraries/animation/src/AnimVariant.cpp | 66 +- libraries/animation/src/AnimVariant.h | 10 +- libraries/animation/src/Rig.cpp | 32 +- libraries/animation/src/Rig.h | 12 +- libraries/audio-client/CMakeLists.txt | 1 + libraries/audio/src/AudioEffectOptions.cpp | 12 +- libraries/audio/src/AudioEffectOptions.h | 8 +- libraries/audio/src/AudioInjectorOptions.cpp | 54 +- libraries/audio/src/AudioInjectorOptions.h | 8 +- libraries/audio/src/ScriptAudioInjector.cpp | 6 +- libraries/audio/src/ScriptAudioInjector.h | 10 +- libraries/audio/src/Sound.cpp | 6 +- libraries/audio/src/Sound.h | 7 +- libraries/avatars/src/AvatarData.cpp | 66 +- libraries/avatars/src/AvatarData.h | 12 +- libraries/avatars/src/ScriptAvatarData.cpp | 4 +- libraries/baking/src/MaterialBaker.cpp | 4 +- .../controllers/src/controllers/Pose.cpp | 32 +- libraries/controllers/src/controllers/Pose.h | 8 +- .../src/controllers/ScriptingInterface.cpp | 6 +- .../src/controllers/UserInputMapper.cpp | 98 +-- .../src/controllers/UserInputMapper.h | 6 +- .../controllers/impl/MappingBuilderProxy.cpp | 6 +- .../controllers/impl/MappingBuilderProxy.h | 6 +- .../controllers/impl/RouteBuilderProxy.cpp | 6 +- .../src/controllers/impl/RouteBuilderProxy.h | 6 +- .../impl/conditionals/ScriptConditional.cpp | 2 +- .../impl/conditionals/ScriptConditional.h | 9 +- .../impl/endpoints/ScriptEndpoint.cpp | 34 +- .../impl/endpoints/ScriptEndpoint.h | 9 +- .../src/ModelScriptingInterface.cpp | 24 +- .../src/ModelScriptingInterface.h | 13 +- .../src/AmbientLightPropertyGroup.cpp | 4 +- .../entities/src/AmbientLightPropertyGroup.h | 6 +- .../entities/src/AnimationPropertyGroup.cpp | 4 +- .../entities/src/AnimationPropertyGroup.h | 6 +- libraries/entities/src/BloomPropertyGroup.cpp | 4 +- libraries/entities/src/BloomPropertyGroup.h | 7 +- libraries/entities/src/EntityEditFilters.cpp | 102 +-- libraries/entities/src/EntityEditFilters.h | 7 +- .../entities/src/EntityItemProperties.cpp | 130 ++-- libraries/entities/src/EntityItemProperties.h | 32 +- .../entities/src/EntityItemPropertiesMacros.h | 228 +++--- .../entities/src/EntityScriptingInterface.cpp | 117 +-- .../entities/src/EntityScriptingInterface.h | 25 +- libraries/entities/src/EntityTree.cpp | 6 +- libraries/entities/src/GrabPropertyGroup.cpp | 4 +- libraries/entities/src/GrabPropertyGroup.h | 7 +- libraries/entities/src/HazePropertyGroup.cpp | 4 +- libraries/entities/src/HazePropertyGroup.h | 7 +- .../entities/src/KeyLightPropertyGroup.cpp | 4 +- .../entities/src/KeyLightPropertyGroup.h | 6 +- libraries/entities/src/PropertyGroup.h | 7 +- libraries/entities/src/PulsePropertyGroup.cpp | 4 +- libraries/entities/src/PulsePropertyGroup.h | 7 +- .../src/RecurseOctreeToJSONOperator.cpp | 6 +- .../src/RecurseOctreeToJSONOperator.h | 6 +- .../src/RecurseOctreeToMapOperator.cpp | 6 +- .../entities/src/RingGizmoPropertyGroup.cpp | 4 +- .../entities/src/RingGizmoPropertyGroup.h | 7 +- .../entities/src/SkyboxPropertyGroup.cpp | 4 +- libraries/entities/src/SkyboxPropertyGroup.h | 7 +- .../GraphicsScriptingInterface.cpp | 148 ++-- .../GraphicsScriptingInterface.h | 6 +- .../GraphicsScriptingUtil.cpp | 22 +- .../GraphicsScriptingUtil.h | 8 +- .../src/graphics-scripting/ScriptableMesh.cpp | 32 +- .../src/graphics-scripting/ScriptableMesh.h | 6 +- .../graphics-scripting/ScriptableMeshPart.cpp | 4 +- .../graphics-scripting/ScriptableMeshPart.h | 7 +- .../graphics-scripting/ScriptableModel.cpp | 2 +- libraries/input-plugins/CMakeLists.txt | 1 + .../recording/RecordingScriptingInterface.cpp | 32 +- .../recording/RecordingScriptingInterface.h | 11 +- libraries/render-utils/CMakeLists.txt | 1 + .../src/AssetScriptingInterface.cpp | 126 +-- .../src/AssetScriptingInterface.h | 45 +- .../src/ConsoleScriptingInterface.cpp | 34 +- .../src/ConsoleScriptingInterface.h | 24 +- libraries/script-engine/src/KeyEvent.cpp | 50 +- libraries/script-engine/src/KeyEvent.h | 9 +- .../src/LocationScriptingInterface.cpp | 6 +- .../src/LocationScriptingInterface.h | 8 +- libraries/script-engine/src/MIDIEvent.cpp | 22 +- libraries/script-engine/src/MIDIEvent.h | 8 +- .../script-engine/src/MenuItemProperties.cpp | 36 +- .../script-engine/src/MenuItemProperties.h | 8 +- libraries/script-engine/src/MouseEvent.cpp | 26 +- libraries/script-engine/src/MouseEvent.h | 11 +- libraries/script-engine/src/PointerEvent.cpp | 112 +-- libraries/script-engine/src/PointerEvent.h | 11 +- libraries/script-engine/src/ScriptContext.h | 14 +- libraries/script-engine/src/ScriptEngine.cpp | 32 +- libraries/script-engine/src/ScriptEngine.h | 74 +- .../script-engine/src/ScriptEngineCast.h | 40 +- libraries/script-engine/src/ScriptManager.cpp | 336 ++++---- libraries/script-engine/src/ScriptManager.h | 45 +- libraries/script-engine/src/ScriptValue.cpp | 236 ++++++ libraries/script-engine/src/ScriptValue.h | 311 +++++--- .../script-engine/src/ScriptValueIterator.h | 2 +- .../script-engine/src/ScriptValueUtils.cpp | 734 +++++++++--------- .../script-engine/src/ScriptValueUtils.h | 136 ++-- libraries/script-engine/src/Scriptable.h | 15 +- libraries/script-engine/src/ScriptsModel.h | 7 +- libraries/script-engine/src/SpatialEvent.cpp | 14 +- libraries/script-engine/src/SpatialEvent.h | 9 +- libraries/script-engine/src/TouchEvent.cpp | 60 +- libraries/script-engine/src/TouchEvent.h | 9 +- .../src/VariantMapToScriptValue.cpp | 16 +- .../src/VariantMapToScriptValue.h | 6 +- .../script-engine/src/WebSocketClass.cpp | 69 +- libraries/script-engine/src/WebSocketClass.h | 53 +- .../src/WebSocketServerClass.cpp | 18 +- .../script-engine/src/WebSocketServerClass.h | 7 +- libraries/script-engine/src/WheelEvent.cpp | 28 +- libraries/script-engine/src/WheelEvent.h | 9 +- .../script-engine/src/XMLHttpRequestClass.cpp | 27 +- .../script-engine/src/XMLHttpRequestClass.h | 52 +- .../src/qtscript/ScriptContextQtWrapper.cpp | 20 +- .../src/qtscript/ScriptContextQtWrapper.h | 14 +- .../src/qtscript/ScriptEngineQtScript.cpp | 188 ++--- .../src/qtscript/ScriptEngineQtScript.h | 66 +- .../qtscript/ScriptValueIteratorQtWrapper.cpp | 4 +- .../qtscript/ScriptValueIteratorQtWrapper.h | 4 +- .../src/qtscript/ScriptValueQtWrapper.cpp | 92 ++- .../src/qtscript/ScriptValueQtWrapper.h | 73 +- libraries/ui/src/QmlFragmentClass.cpp | 12 +- libraries/ui/src/QmlFragmentClass.h | 12 +- libraries/ui/src/QmlWebWindowClass.cpp | 2 +- libraries/ui/src/QmlWebWindowClass.h | 10 +- libraries/ui/src/QmlWindowClass.cpp | 20 +- libraries/ui/src/QmlWindowClass.h | 12 +- libraries/ui/src/ui/QmlWrapper.h | 11 +- .../ui/src/ui/ToolbarScriptingInterface.cpp | 12 +- plugins/JSAPIExample/src/JSAPIExample.cpp | 11 +- plugins/hifiNeuron/CMakeLists.txt | 1 + plugins/hifiOsc/CMakeLists.txt | 1 + plugins/hifiSdl2/CMakeLists.txt | 1 + plugins/oculus/CMakeLists.txt | 1 + 170 files changed, 2835 insertions(+), 2598 deletions(-) create mode 100644 libraries/script-engine/src/ScriptValue.cpp diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index f74a533464f..20453274779 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -505,8 +505,8 @@ void Agent::executeScript() { scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); - ScriptValuePointer webSocketServerConstructorValue = scriptEngine->newFunction(WebSocketServerClass::constructor); - scriptEngine->globalObject()->setProperty("WebSocketServer", webSocketServerConstructorValue); + ScriptValue webSocketServerConstructorValue = scriptEngine->newFunction(WebSocketServerClass::constructor); + scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); auto entityScriptingInterface = DependencyManager::get(); diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index b0278e9bdca..17536ffc974 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -452,7 +452,7 @@ void EntityScriptServer::resetEntitiesScriptEngine() { auto newEngine = newManager->engine(); auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor); - newEngine->globalObject()->setProperty("WebSocketServer", webSocketServerConstructorValue); + newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); newEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); newEngine->registerGlobalObject("AvatarList", DependencyManager::get().data()); diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 8b3aef514f1..35ac531c810 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -54,7 +54,7 @@ void addAvatarEntities(const QVariantList& avatarEntities) { const QVariantMap& avatarEntityProperties = avatarEntities.at(index).toMap(); QVariant variantProperties = avatarEntityProperties["properties"]; QVariantMap asMap = variantProperties.toMap(); - ScriptValuePointer scriptProperties = variantMapToScriptValue(asMap, *scriptEngine); + ScriptValue scriptProperties = variantMapToScriptValue(asMap, *scriptEngine); EntityItemProperties entityProperties; EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptProperties, entityProperties); @@ -318,8 +318,8 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { desiredProperties -= PROP_JOINT_TRANSLATIONS; EntityItemProperties entityProperties = entity->getProperties(desiredProperties); - ScriptValuePointer scriptProperties = EntityItemPropertiesToScriptValue(scriptEngine.get(), entityProperties); - avatarEntityData["properties"] = scriptProperties->toVariant(); + ScriptValue scriptProperties = EntityItemPropertiesToScriptValue(scriptEngine.get(), entityProperties); + avatarEntityData["properties"] = scriptProperties.toVariant(); wearableEntities.append(QVariant(avatarEntityData)); } } diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index d5da45341bc..9a80c5478b7 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -426,13 +426,13 @@ WorldDetailQuality LODManager::getWorldDetailQuality() const { return qApp->isHMDMode() ? _hmdWorldDetailQuality : _desktopWorldDetailQuality; } -ScriptValuePointer worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality) { +ScriptValue worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality) { return engine->newValue(worldDetailQuality); } -void worldDetailQualityFromScriptValue(const ScriptValuePointer& object, WorldDetailQuality& worldDetailQuality) { +void worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality) { worldDetailQuality = - static_cast(std::min(std::max(object->toInt32(), (int)WORLD_DETAIL_LOW), (int)WORLD_DETAIL_HIGH)); + static_cast(std::min(std::max(object.toInt32(), (int)WORLD_DETAIL_LOW), (int)WORLD_DETAIL_HIGH)); } void LODManager::setLODQualityLevel(float quality) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 52a1c3ea440..1ab64b2dc16 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -14,7 +14,6 @@ #define hifi_LODManager_h #include -#include #include #include @@ -23,10 +22,9 @@ #include #include #include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc *

The world detail quality rendered.

@@ -384,7 +382,7 @@ class LODManager : public QObject, public Dependency { glm::vec4 _pidOutputs{ 0.0f }; }; -ScriptValuePointer worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality); -void worldDetailQualityFromScriptValue(const ScriptValuePointer& object, WorldDetailQuality& worldDetailQuality); +ScriptValue worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality); +void worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality); #endif // hifi_LODManager_h diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 915adc03677..191770642bf 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -736,8 +736,8 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) } RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& ray, - const ScriptValuePointer& avatarIdsToInclude, - const ScriptValuePointer& avatarIdsToDiscard, + const ScriptValue& avatarIdsToInclude, + const ScriptValue& avatarIdsToDiscard, bool pickAgainstMesh) { QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); @@ -981,10 +981,10 @@ float AvatarManager::getAvatarSortCoefficient(const QString& name) { } // HACK -void AvatarManager::setAvatarSortCoefficient(const QString& name, const ScriptValuePointer& value) { +void AvatarManager::setAvatarSortCoefficient(const QString& name, const ScriptValue& value) { bool somethingChanged = false; - if (value->isNumber()) { - float numericalValue = (float)value->toNumber(); + if (value.isNumber()) { + float numericalValue = (float)value.toNumber(); if (name == "size") { AvatarData::_avatarSortCoefficientSize = numericalValue; somethingChanged = true; diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 2340e553a44..e2784008211 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -16,7 +16,6 @@ #include #include -#include #include #include @@ -27,6 +26,7 @@ #include #include #include // for SetOfEntities +#include #include "AvatarMotionState.h" #include "DetailedMotionState.h" @@ -34,9 +34,7 @@ #include "OtherAvatar.h" class ScriptEngine; -class ScriptValue; using SortedAvatar = std::pair>; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The AvatarManager API provides information about avatars within the current domain. The avatars available are @@ -188,8 +186,8 @@ class AvatarManager : public AvatarHashMap { * } */ Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, - const ScriptValuePointer& avatarIdsToInclude = ScriptValuePointer(), - const ScriptValuePointer& avatarIdsToDiscard = ScriptValuePointer(), + const ScriptValue& avatarIdsToInclude = ScriptValue(), + const ScriptValue& avatarIdsToDiscard = ScriptValue(), bool pickAgainstMesh = true); /*@jsdoc * @function AvatarManager.findRayIntersectionVector @@ -232,7 +230,7 @@ class AvatarManager : public AvatarHashMap { * @param {number} value - Value. * @deprecated This function is deprecated and will be removed. */ - Q_INVOKABLE void setAvatarSortCoefficient(const QString& name, const ScriptValuePointer& value); + Q_INVOKABLE void setAvatarSortCoefficient(const QString& name, const ScriptValue& value); /*@jsdoc * Gets PAL (People Access List) data for one or more avatars. Using this method is faster than iterating over each avatar diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index af3efb4b848..7643dc48ce2 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -439,15 +439,15 @@ void MyAvatar::enableHandTouchForID(const QUuid& entityID) { } void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) { - ScriptValuePointer value = engine->newQObject(this, ScriptEngine::QtOwnership); - engine->globalObject()->setProperty("MyAvatar", value); + ScriptValue value = engine->newQObject(this, ScriptEngine::QtOwnership); + engine->globalObject().setProperty("MyAvatar", value); - ScriptValuePointer driveKeys = engine->newObject(); + ScriptValue driveKeys = engine->newObject(); auto metaEnum = QMetaEnum::fromType(); for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { - driveKeys->setProperty(metaEnum.key(i), metaEnum.value(i)); + driveKeys.setProperty(metaEnum.key(i), metaEnum.value(i)); } - engine->globalObject()->setProperty("DriveKeys", driveKeys); + engine->globalObject().setProperty("DriveKeys", driveKeys); scriptRegisterMetaType(engine.data(), audioListenModeToScriptValue, audioListenModeFromScriptValue); scriptRegisterMetaType(engine.data(), driveKeysToScriptValue, driveKeysFromScriptValue); @@ -2670,8 +2670,8 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() { EntityItemProperties entityProperties = entity->getProperties(desiredProperties); { std::lock_guard guard(_scriptEngineLock); - ScriptValuePointer scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties); - avatarEntityData["properties"] = scriptProperties->toVariant(); + ScriptValue scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties); + avatarEntityData["properties"] = scriptProperties.toVariant(); } avatarEntitiesData.append(QVariant(avatarEntityData)); } @@ -5702,20 +5702,20 @@ void MyAvatar::setAudioListenerMode(AudioListenerMode audioListenerMode) { } } -ScriptValuePointer audioListenModeToScriptValue(ScriptEngine* engine, const AudioListenerMode& audioListenerMode) { +ScriptValue audioListenModeToScriptValue(ScriptEngine* engine, const AudioListenerMode& audioListenerMode) { return engine->newValue(audioListenerMode); } -void audioListenModeFromScriptValue(const ScriptValuePointer& object, AudioListenerMode& audioListenerMode) { - audioListenerMode = static_cast(object->toUInt16()); +void audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode) { + audioListenerMode = static_cast(object.toUInt16()); } -ScriptValuePointer driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys) { +ScriptValue driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys) { return engine->newValue(driveKeys); } -void driveKeysFromScriptValue(const ScriptValuePointer& object, MyAvatar::DriveKeys& driveKeys) { - driveKeys = static_cast(object->toUInt16()); +void driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys) { + driveKeys = static_cast(object.toUInt16()); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8b5ddd7e15d..8008da631a4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "AtRestDetector.h" #include "MyCharacterController.h" @@ -41,8 +42,6 @@ class ModelItemID; class MyHead; class DetailedMotionState; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; using ScriptEnginePointer = QSharedPointer; /*@jsdoc @@ -872,7 +871,7 @@ class MyAvatar : public Avatar { * MyAvatar.removeAnimationStateHandler(handler); * }, 100); */ - Q_INVOKABLE ScriptValuePointer addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList) { return _skeletonModel->getRig().addAnimationStateHandler(handler, propertiesList); } + Q_INVOKABLE ScriptValue addAnimationStateHandler(const ScriptValue& handler, const ScriptValue& propertiesList) { return _skeletonModel->getRig().addAnimationStateHandler(handler, propertiesList); } /*@jsdoc * Removes an animation state handler function. @@ -880,7 +879,7 @@ class MyAvatar : public Avatar { * @param {number} handler - The ID of the animation state handler function to remove. */ // Removes a handler previously added by addAnimationStateHandler. - Q_INVOKABLE void removeAnimationStateHandler(ScriptValuePointer handler) { _skeletonModel->getRig().removeAnimationStateHandler(handler); } + Q_INVOKABLE void removeAnimationStateHandler(const ScriptValue& handler) { _skeletonModel->getRig().removeAnimationStateHandler(handler); } /*@jsdoc @@ -3118,11 +3117,11 @@ private slots: QTimer _addAvatarEntitiesToTreeTimer; }; -ScriptValuePointer audioListenModeToScriptValue(ScriptEngine* engine, const AudioListenerMode& audioListenerMode); -void audioListenModeFromScriptValue(const ScriptValuePointer& object, AudioListenerMode& audioListenerMode); +ScriptValue audioListenModeToScriptValue(ScriptEngine* engine, const AudioListenerMode& audioListenerMode); +void audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode); -ScriptValuePointer driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys); -void driveKeysFromScriptValue(const ScriptValuePointer& object, MyAvatar::DriveKeys& driveKeys); +ScriptValue driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys); +void driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys); bool isWearableEntity(const EntityItemPointer& entity); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 5aacd724594..ed5fd2ecb69 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -14,11 +14,11 @@ #include "PointerScriptingInterface.h" #include -void LaserPointerScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems) const { +void LaserPointerScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValue& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void LaserPointerScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems) const { +void LaserPointerScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValue& includeItems) const { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 9796508ca95..fe70509a0c8 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -12,13 +12,11 @@ #define hifi_LaserPointerScriptingInterface_h #include -#include #include "DependencyManager.h" #include class ScriptValue; -using ScriptValuePointer = QSharedPointer; class LaserPointerScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -117,7 +115,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pointer. * @param {Uuid[]} ignoreItems - A list of IDs to ignore. */ - Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreEntities) const; + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValue& ignoreEntities) const; /*@jsdoc * Sets a list of entity and avatar IDs that a pointer should include during intersection, instead of intersecting with @@ -126,7 +124,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pointer. * @param {Uuid[]} includeItems - A list of IDs to include. */ - Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValuePointer& includeEntities) const; + Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValue& includeEntities) const; /*@jsdoc diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 954b6be3eab..eba2dec19e8 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -427,11 +427,11 @@ void PickScriptingInterface::setPrecisionPicking(unsigned int uid, bool precisio DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } -void PickScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems) { +void PickScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValue& ignoreItems) { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void PickScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems) { +void PickScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValue& includeItems) { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } @@ -447,21 +447,21 @@ bool PickScriptingInterface::isMouse(unsigned int uid) { return DependencyManager::get()->isMouse(uid); } -ScriptValuePointer pickTypesToScriptValue(ScriptEngine* engine, const PickQuery::PickType& pickType) { +ScriptValue pickTypesToScriptValue(ScriptEngine* engine, const PickQuery::PickType& pickType) { return engine->newValue(pickType); } -void pickTypesFromScriptValue(const ScriptValuePointer& object, PickQuery::PickType& pickType) { - pickType = static_cast(object->toUInt16()); +void pickTypesFromScriptValue(const ScriptValue& object, PickQuery::PickType& pickType) { + pickType = static_cast(object.toUInt16()); } void PickScriptingInterface::registerMetaTypes(ScriptEngine* engine) { - ScriptValuePointer pickTypes = engine->newObject(); + ScriptValue pickTypes = engine->newObject(); auto metaEnum = QMetaEnum::fromType(); for (int i = 0; i < PickQuery::PickType::NUM_PICK_TYPES; ++i) { - pickTypes->setProperty(metaEnum.key(i), metaEnum.value(i)); + pickTypes.setProperty(metaEnum.key(i), metaEnum.value(i)); } - engine->globalObject()->setProperty("PickType", pickTypes); + engine->globalObject().setProperty("PickType", pickTypes); scriptRegisterMetaType(engine, pickTypesToScriptValue, pickTypesFromScriptValue); } diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 2ce8b2026c0..8afe5c45d35 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -9,7 +9,6 @@ #define hifi_PickScriptingInterface_h #include -#include #include #include @@ -18,7 +17,6 @@ class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The Picks API lets you create and manage objects for repeatedly calculating intersections. @@ -250,7 +248,7 @@ class PickScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pick. * @param {Uuid[]} ignoreItems - The list of IDs to ignore. */ - Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems); + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValue& ignoreItems); /*@jsdoc * Sets a list of entity and avatar IDs that a pick should include during intersection, instead of intersecting with @@ -260,7 +258,7 @@ class PickScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pick. * @param {Uuid[]} includeItems - The list of IDs to include. */ - Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems); + Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValue& includeItems); /*@jsdoc * Checks if a pick is associated with the left hand: a ray or parabola pick with joint property set to diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 58fc736bb98..259fbf428d8 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -25,11 +25,11 @@ static const glm::quat X_ROT_NEG_90{ 0.70710678f, -0.70710678f, 0.0f, 0.0f }; static const glm::vec3 DEFAULT_POSITION_OFFSET{0.0f, 0.0f, -StylusPick::WEB_STYLUS_LENGTH / 2.0f}; static const glm::vec3 DEFAULT_MODEL_DIMENSIONS{0.01f, 0.01f, StylusPick::WEB_STYLUS_LENGTH}; -void PointerScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems) const { +void PointerScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValue& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void PointerScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems) const { +void PointerScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValue& includeItems) const { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 226e10433ad..836a86b7bdd 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -9,7 +9,6 @@ #define hifi_PointerScriptingInterface_h #include -#include #include "DependencyManager.h" #include "RegisteredMetaTypes.h" @@ -17,7 +16,6 @@ #include class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The Pointers API lets you create, manage, and visually represent objects for repeatedly calculating @@ -369,7 +367,7 @@ class PointerScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pointer. * @param {Uuid[]} ignoreItems - A list of IDs to ignore. */ - Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreEntities) const; + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValue& ignoreEntities) const; /*@jsdoc * Sets a list of entity and avatar IDs that a pointer should include during intersection, instead of intersecting with @@ -379,7 +377,7 @@ class PointerScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the pointer. * @param {Uuid[]} includeItems - A list of IDs to include. */ - Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValuePointer& includeEntities) const; + Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValue& includeEntities) const; /*@jsdoc diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index 1ddbb487665..6371632368a 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -46,11 +46,11 @@ void RayPickScriptingInterface::setPrecisionPicking(unsigned int uid, bool preci DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } -void RayPickScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreItems) { +void RayPickScriptingInterface::setIgnoreItems(unsigned int uid, const ScriptValue& ignoreItems) { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void RayPickScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValuePointer& includeItems) { +void RayPickScriptingInterface::setIncludeItems(unsigned int uid, const ScriptValue& includeItems) { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index 33f6fe099ee..acc11111c76 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -12,7 +12,6 @@ #define hifi_RayPickScriptingInterface_h #include -#include #include "RegisteredMetaTypes.h" #include @@ -20,7 +19,6 @@ #include "PickScriptingInterface.h" class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The RayPick API is a subset of the {@link Picks} API, as used for ray picks. @@ -125,7 +123,7 @@ class RayPickScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the ray pick. * @param {Uuid[]} ignoreItems - The list of IDs to ignore. */ - Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValuePointer& ignoreEntities); + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const ScriptValue& ignoreEntities); /*@jsdoc * Sets a list of entity and avatar IDs that a ray pick should include during intersection, instead of intersecting with @@ -134,7 +132,7 @@ class RayPickScriptingInterface : public QObject, public Dependency { * @param {number} id - The ID of the ray pick. * @param {Uuid[]} includeItems - The list of IDs to include. */ - Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValuePointer& includeEntities); + Q_INVOKABLE void setIncludeItems(unsigned int uid, const ScriptValue& includeEntities); /*@jsdoc diff --git a/interface/src/scripting/AccountServicesScriptingInterface.cpp b/interface/src/scripting/AccountServicesScriptingInterface.cpp index e889bf7aa1f..ccd4ca83393 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.cpp +++ b/interface/src/scripting/AccountServicesScriptingInterface.cpp @@ -118,27 +118,27 @@ DownloadInfoResult::DownloadInfoResult() : * @property {number[]} downloading - The download percentage remaining of each asset currently downloading. * @property {number} pending - The number of assets pending download. */ -ScriptValuePointer DownloadInfoResultToScriptValue(ScriptEngine* engine, const DownloadInfoResult& result) { - ScriptValuePointer object = engine->newObject(); +ScriptValue DownloadInfoResultToScriptValue(ScriptEngine* engine, const DownloadInfoResult& result) { + ScriptValue object = engine->newObject(); - ScriptValuePointer array = engine->newArray(result.downloading.count()); + ScriptValue array = engine->newArray(result.downloading.count()); for (int i = 0; i < result.downloading.count(); i += 1) { - array->setProperty(i, result.downloading[i]); + array.setProperty(i, result.downloading[i]); } - object->setProperty("downloading", array); - object->setProperty("pending", result.pending); + object.setProperty("downloading", array); + object.setProperty("pending", result.pending); return object; } -void DownloadInfoResultFromScriptValue(const ScriptValuePointer& object, DownloadInfoResult& result) { - QList downloading = object->property("downloading")->toVariant().toList(); +void DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result) { + QList downloading = object.property("downloading").toVariant().toList(); result.downloading.clear(); for (int i = 0; i < downloading.count(); i += 1) { result.downloading.append(downloading[i].toFloat()); } - result.pending = object->property("pending")->toVariant().toFloat(); + result.pending = object.property("pending").toVariant().toFloat(); } DownloadInfoResult AccountServicesScriptingInterface::getDownloadInfo() { diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index 8e66b894cb5..b9d453395d5 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -15,14 +15,12 @@ #include #include #include -#include #include #include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class DownloadInfoResult { public: @@ -33,8 +31,8 @@ class DownloadInfoResult { Q_DECLARE_METATYPE(DownloadInfoResult) -ScriptValuePointer DownloadInfoResultToScriptValue(ScriptEngine* engine, const DownloadInfoResult& result); -void DownloadInfoResultFromScriptValue(const ScriptValuePointer& object, DownloadInfoResult& result); +ScriptValue DownloadInfoResultToScriptValue(ScriptEngine* engine, const DownloadInfoResult& result); +void DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result); class AccountServicesScriptingInterface : public QObject { Q_OBJECT diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index cca69548199..609037b7149 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -152,7 +152,7 @@ bool HMDScriptingInterface::getAwayStateWhenFocusLostInVREnabled() { } -ScriptValuePointer HMDScriptingInterface::getHUDLookAtPosition2D(ScriptContext* context, ScriptEngine* engine) { +ScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(ScriptContext* context, ScriptEngine* engine) { glm::vec3 hudIntersection; auto instance = DependencyManager::get(); if (instance->getHUDLookAtPosition3D(hudIntersection)) { @@ -162,7 +162,7 @@ ScriptValuePointer HMDScriptingInterface::getHUDLookAtPosition2D(ScriptContext* return engine->nullValue(); } -ScriptValuePointer HMDScriptingInterface::getHUDLookAtPosition3D(ScriptContext* context, ScriptEngine* engine) { +ScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(ScriptContext* context, ScriptEngine* engine) { glm::vec3 result; auto instance = DependencyManager::get(); if (instance->getHUDLookAtPosition3D(result)) { diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index d7fb0b3dce7..ad0bcad1002 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -19,12 +19,10 @@ #include #include -#include +#include class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The HMD API provides access to the HMD used in VR display mode. @@ -444,14 +442,14 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen * @function HMD.getHUDLookAtPosition2D * @returns {Vec2} The position on the HUD overlay that your HMD is looking at, in pixels. */ - static ScriptValuePointer getHUDLookAtPosition2D(ScriptContext* context, ScriptEngine* engine); + static ScriptValue getHUDLookAtPosition2D(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Gets the position on the HUD overlay that your HMD is looking at, in world coordinates. * @function HMD.getHUDLookAtPosition3D * @returns {Vec3} The position on the HUD overlay the your HMD is looking at, in world coordinates. */ - static ScriptValuePointer getHUDLookAtPosition3D(ScriptContext* context, ScriptEngine* engine); + static ScriptValue getHUDLookAtPosition3D(ScriptContext* context, ScriptEngine* engine); bool isMounted() const override; diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 1b7ef709e07..2985ae6e50e 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -154,9 +154,9 @@ void TestScriptingInterface::savePhysicsSimulationStats(QString originalPath) { qApp->saveNextPhysicsStats(path); } -void TestScriptingInterface::profileRange(const QString& name, ScriptValuePointer fn) { +void TestScriptingInterface::profileRange(const QString& name, const ScriptValue& fn) { PROFILE_RANGE(script, name); - fn->call(); + fn.call(); } void TestScriptingInterface::clearCaches() { diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index 2bc2092396a..b5305d1df2a 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -12,10 +12,7 @@ #include #include -#include - -class ScriptValue; -using ScriptValuePointer = QSharedPointer; +#include class TestScriptingInterface : public QObject { Q_OBJECT @@ -129,7 +126,7 @@ public slots: * @param {string} name - Name used to reference the function * @param {function} function - Function to profile */ - Q_INVOKABLE void profileRange(const QString& name, ScriptValuePointer function); + Q_INVOKABLE void profileRange(const QString& name, const ScriptValue& function); /*@jsdoc * Clear all caches (menu command Reload Content) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index c54ce5b37b7..cdc3fdb09a5 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -76,7 +76,7 @@ WindowScriptingInterface::~WindowScriptingInterface() { _messageBoxes.clear(); } -ScriptValuePointer WindowScriptingInterface::hasFocus() { +ScriptValue WindowScriptingInterface::hasFocus() { return engine()->newValue(qApp->hasFocus()); } @@ -96,26 +96,26 @@ void WindowScriptingInterface::raise() { /// Display an alert box /// \param const QString& message message to display -/// \return ScriptValuePointer::UndefinedValue +/// \return ScriptValue::UndefinedValue void WindowScriptingInterface::alert(const QString& message) { OffscreenUi::asyncWarning("", message, QMessageBox::Ok, QMessageBox::Ok); } /// Display a confirmation box with the options 'Yes' and 'No' /// \param const QString& message message to display -/// \return ScriptValuePointer `true` if 'Yes' was clicked, `false` otherwise -ScriptValuePointer WindowScriptingInterface::confirm(const QString& message) { +/// \return ScriptValue `true` if 'Yes' was clicked, `false` otherwise +ScriptValue WindowScriptingInterface::confirm(const QString& message) { return engine()->newValue((QMessageBox::Yes == OffscreenUi::question("", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))); } /// Display a prompt with a text box /// \param const QString& message message to display /// \param const QString& defaultText default text in the text box -/// \return ScriptValuePointer string text value in text box if the dialog was accepted, `null` otherwise. -ScriptValuePointer WindowScriptingInterface::prompt(const QString& message, const QString& defaultText) { +/// \return ScriptValue string text value in text box if the dialog was accepted, `null` otherwise. +ScriptValue WindowScriptingInterface::prompt(const QString& message, const QString& defaultText) { QString result = OffscreenUi::getText(nullptr, "", message, QLineEdit::Normal, defaultText); auto sResult = engine()->newValue(result); - if (sResult->equals(engine()->newValue(""))) { + if (sResult.equals(engine()->newValue(""))) { return engine()->nullValue(); } return sResult; @@ -218,8 +218,8 @@ void WindowScriptingInterface::ensureReticleVisible() const { /// working directory. /// \param const QString& title title of the window /// \param const QString& directory directory to start the directory browser at -/// \return ScriptValuePointer file path as a string if one was selected, otherwise `ScriptValuePointer::NullValue` -ScriptValuePointer WindowScriptingInterface::browseDir(const QString& title, const QString& directory) { +/// \return ScriptValue file path as a string if one was selected, otherwise `ScriptValue::NullValue` +ScriptValue WindowScriptingInterface::browseDir(const QString& title, const QString& directory) { ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { @@ -262,8 +262,8 @@ void WindowScriptingInterface::browseDirAsync(const QString& title, const QStrin /// \param const QString& title title of the window /// \param const QString& directory directory to start the file browser at /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` -/// \return ScriptValuePointer file path as a string if one was selected, otherwise `ScriptValuePointer::NullValue` -ScriptValuePointer WindowScriptingInterface::browse(const QString& title, const QString& directory, const QString& nameFilter) { +/// \return ScriptValue file path as a string if one was selected, otherwise `ScriptValue::NullValue` +ScriptValue WindowScriptingInterface::browse(const QString& title, const QString& directory, const QString& nameFilter) { ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { @@ -309,8 +309,8 @@ void WindowScriptingInterface::browseAsync(const QString& title, const QString& /// \param const QString& title title of the window /// \param const QString& directory directory to start the file browser at /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` -/// \return ScriptValuePointer file path as a string if one was selected, otherwise `ScriptValuePointer::NullValue` -ScriptValuePointer WindowScriptingInterface::save(const QString& title, const QString& directory, const QString& nameFilter) { +/// \return ScriptValue file path as a string if one was selected, otherwise `ScriptValue::NullValue` +ScriptValue WindowScriptingInterface::save(const QString& title, const QString& directory, const QString& nameFilter) { ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { @@ -356,8 +356,8 @@ void WindowScriptingInterface::saveAsync(const QString& title, const QString& di /// \param const QString& title title of the window /// \param const QString& directory directory to start the asset browser at /// \param const QString& nameFilter filter to filter asset names by - see `QFileDialog` -/// \return ScriptValuePointer asset path as a string if one was selected, otherwise `ScriptValuePointer::NullValue` -ScriptValuePointer WindowScriptingInterface::browseAssets(const QString& title, const QString& directory, const QString& nameFilter) { +/// \return ScriptValue asset path as a string if one was selected, otherwise `ScriptValue::NullValue` +ScriptValue WindowScriptingInterface::browseAssets(const QString& title, const QString& directory, const QString& nameFilter) { ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 418869519f6..6e7b495db9f 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -18,15 +18,12 @@ #include #include #include -#include #include #include +#include -class ScriptValue; -using ScriptValuePointer = QSharedPointer; - /*@jsdoc * The Window API provides various facilities not covered elsewhere, including: window dimensions, window focus, * camera view, announcements, user connections, common dialog boxes, snapshots, file import, domain navigation, domain changes, @@ -74,7 +71,7 @@ public slots: * @function Window.hasFocus * @returns {boolean} true if the Interface window has focus, false if it doesn't. */ - ScriptValuePointer hasFocus(); + ScriptValue hasFocus(); /*@jsdoc * Makes the Interface window have focus. On Windows, if Interface doesn't already have focus, the task bar icon flashes to @@ -109,7 +106,7 @@ public slots: * var answer = Window.confirm("Are you sure?"); * print(answer); // true or false */ - ScriptValuePointer confirm(const QString& message = ""); + ScriptValue confirm(const QString& message = ""); /*@jsdoc * Prompts the user to enter some text. Displays a modal dialog with a message and a text box, plus "OK" and "Cancel" @@ -126,7 +123,7 @@ public slots: * print("User answer: " + answer); * } */ - ScriptValuePointer prompt(const QString& message, const QString& defaultText); + ScriptValue prompt(const QString& message, const QString& defaultText); /*@jsdoc * Prompts the user to enter some text. Displays a non-modal dialog with a message and a text box, plus "OK" and "Cancel" @@ -156,7 +153,7 @@ public slots: * var directory = Window.browseDir("Select Directory", Paths.resources); * print("Directory: " + directory); */ - ScriptValuePointer browseDir(const QString& title = "", const QString& directory = ""); + ScriptValue browseDir(const QString& title = "", const QString& directory = ""); /*@jsdoc * Prompts the user to choose a directory. Displays a non-modal dialog that navigates the directory tree. A @@ -188,7 +185,7 @@ public slots: * var filename = Window.browse("Select Image File", Paths.resources, "Images (*.png *.jpg *.svg)"); * print("File: " + filename); */ - ScriptValuePointer browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + ScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); /*@jsdoc * Prompts the user to choose a file. Displays a non-modal dialog that navigates the directory tree. A @@ -224,7 +221,7 @@ public slots: * var filename = Window.save("Save to JSON file", Paths.resources, "*.json"); * print("File: " + filename); */ - ScriptValuePointer save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + ScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); /*@jsdoc * Prompts the user to specify the path and name of a file to save to. Displays a non-modal dialog that navigates the @@ -259,7 +256,7 @@ public slots: * var asset = Window.browseAssets("Select FBX File", "/", "*.fbx"); * print("FBX file: " + asset); */ - ScriptValuePointer browseAssets(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); + ScriptValue browseAssets(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); /*@jsdoc * Prompts the user to choose an Asset Server item. Displays a non-modal dialog that navigates the tree of assets on the diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index e86b6676963..f74c61dea32 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -97,15 +97,13 @@ void registerInteractiveWindowMetaType(ScriptEngine* engine) { scriptRegisterMetaType(engine, interactiveWindowPointerToScriptValue, interactiveWindowPointerFromScriptValue); } -ScriptValuePointer interactiveWindowPointerToScriptValue(ScriptEngine* engine, const InteractiveWindowPointer& in) { +ScriptValue interactiveWindowPointerToScriptValue(ScriptEngine* engine, const InteractiveWindowPointer& in) { return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void interactiveWindowPointerFromScriptValue(const ScriptValuePointer& object, InteractiveWindowPointer& out) { - if (!object) { - if (const auto interactiveWindow = qobject_cast(object->toQObject())) { - out = interactiveWindow; - } +void interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out) { + if (const auto interactiveWindow = qobject_cast(object.toQObject())) { + out = interactiveWindow; } } diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h index 160ddb122ce..f11140b3c33 100644 --- a/interface/src/ui/InteractiveWindow.h +++ b/interface/src/ui/InteractiveWindow.h @@ -15,17 +15,15 @@ #define hifi_InteractiveWindow_h #include -#include #include #include #include #include #include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class QmlWindowProxy : public QmlWrapper { Q_OBJECT @@ -412,8 +410,8 @@ protected slots: typedef InteractiveWindow* InteractiveWindowPointer; -ScriptValuePointer interactiveWindowPointerToScriptValue(ScriptEngine* engine, const InteractiveWindowPointer& in); -void interactiveWindowPointerFromScriptValue(const ScriptValuePointer& object, InteractiveWindowPointer& out); +ScriptValue interactiveWindowPointerToScriptValue(ScriptEngine* engine, const InteractiveWindowPointer& in); +void interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out); void registerInteractiveWindowMetaType(ScriptEngine* engine); diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index de352598168..71472d439ad 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -187,7 +187,7 @@ JSConsole::JSConsole(QWidget* parent, const ScriptManagerPointer& scriptManager) resizeTextInput(); - connect(&_executeWatcher, &QFutureWatcher::finished, this, &JSConsole::commandFinished); + connect(&_executeWatcher, &QFutureWatcher::finished, this, &JSConsole::commandFinished); } void JSConsole::insertCompletion(const QModelIndex& completion) { @@ -351,12 +351,12 @@ void JSConsole::executeCommand(const QString& command) { QWeakPointer weakScriptManager = _scriptManager; auto consoleFileName = _consoleFileName; - QFuture future = QtConcurrent::run([weakScriptManager, consoleFileName, command]() -> ScriptValuePointer { - ScriptValuePointer result; + QFuture future = QtConcurrent::run([weakScriptManager, consoleFileName, command]() -> ScriptValue { + ScriptValue result; auto scriptManager = weakScriptManager.lock(); if (scriptManager) { BLOCKING_INVOKE_METHOD(scriptManager.data(), "evaluate", - Q_RETURN_ARG(ScriptValuePointer, result), + Q_RETURN_ARG(ScriptValue, result), Q_ARG(const QString&, command), Q_ARG(const QString&, consoleFileName)); } @@ -366,7 +366,7 @@ void JSConsole::executeCommand(const QString& command) { } void JSConsole::commandFinished() { - ScriptValuePointer result = _executeWatcher.result(); + ScriptValue result = _executeWatcher.result(); _ui->promptTextEdit->setDisabled(false); @@ -375,10 +375,10 @@ void JSConsole::commandFinished() { _ui->promptTextEdit->setFocus(); } - bool error = (_scriptManager->engine()->hasUncaughtException() || (result && result->isError())); + bool error = (_scriptManager->engine()->hasUncaughtException() || result.isError()); QString gutter = error ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND; QString resultColor = error ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE; - QString resultStr = result ? "" + result->toString().toHtmlEscaped() + "" : ""; + QString resultStr = "" + result.toString().toHtmlEscaped() + ""; appendMessage(gutter, resultStr); resetCurrentCommandHistory(); diff --git a/interface/src/ui/JSConsole.h b/interface/src/ui/JSConsole.h index 3b9ee9121af..73ca86c5b7b 100644 --- a/interface/src/ui/JSConsole.h +++ b/interface/src/ui/JSConsole.h @@ -17,14 +17,13 @@ #include #include #include +#include #include "ui_console.h" class QStandardItemModel; class ScriptManager; -class ScriptValue; using ScriptManagerPointer = QSharedPointer; -using ScriptValuePointer = QSharedPointer; const QString CONSOLE_TITLE = "Scripting Console"; const float CONSOLE_WINDOW_OPACITY = 0.95f; @@ -72,7 +71,7 @@ private slots: QStandardItemModel* getAutoCompleteModel(const QString& memberOf = nullptr); - QFutureWatcher _executeWatcher; + QFutureWatcher _executeWatcher; Ui::Console* _ui; int _currentCommandInHistory; QString _savedHistoryFilename; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 1db633d1a7f..a2f774e77a0 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -633,7 +633,7 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove } ScriptEnginePointer scriptEngine = newScriptEngine(); - ScriptValuePointer props = variantMapToScriptValue(overlayProps, *scriptEngine); + ScriptValue props = variantMapToScriptValue(overlayProps, *scriptEngine); EntityItemProperties toReturn; EntityItemPropertiesFromScriptValueHonorReadOnly(props, toReturn); return toReturn; @@ -641,7 +641,7 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemProperties& properties) { ScriptEnginePointer scriptEngine = newScriptEngine(); - QVariantMap overlayProps = EntityItemPropertiesToScriptValue(scriptEngine.data(), properties)->toVariant().toMap(); + QVariantMap overlayProps = EntityItemPropertiesToScriptValue(scriptEngine.data(), properties).toVariant().toMap(); QString type = overlayProps["type"].toString(); overlayProps["type"] = entityToOverlayType(type); @@ -1041,8 +1041,8 @@ QVariantMap Overlays::getOverlaysProperties(const QVariant& propertiesById) { } RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, bool precisionPicking, - const ScriptValuePointer& overlayIDsToInclude, - const ScriptValuePointer& overlayIDsToDiscard, + const ScriptValue& overlayIDsToInclude, + const ScriptValue& overlayIDsToDiscard, bool visibleOnly, bool collidableOnly) { const QVector include = qVectorEntityItemIDFromScriptValue(overlayIDsToInclude); const QVector discard = qVectorEntityItemIDFromScriptValue(overlayIDsToDiscard); @@ -1110,38 +1110,38 @@ ParabolaToOverlayIntersectionResult Overlays::findParabolaIntersectionVector(con return overlayResult; } -ScriptValuePointer RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("intersects", value.intersects); - ScriptValuePointer overlayIDValue = quuidToScriptValue(engine, value.overlayID); - obj->setProperty("overlayID", overlayIDValue); - obj->setProperty("distance", value.distance); - obj->setProperty("face", boxFaceToString(value.face)); - - ScriptValuePointer intersection = vec3ToScriptValue(engine, value.intersection); - obj->setProperty("intersection", intersection); - ScriptValuePointer surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); - obj->setProperty("surfaceNormal", surfaceNormal); - obj->setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); +ScriptValue RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value) { + ScriptValue obj = engine->newObject(); + obj.setProperty("intersects", value.intersects); + ScriptValue overlayIDValue = quuidToScriptValue(engine, value.overlayID); + obj.setProperty("overlayID", overlayIDValue); + obj.setProperty("distance", value.distance); + obj.setProperty("face", boxFaceToString(value.face)); + + ScriptValue intersection = vec3ToScriptValue(engine, value.intersection); + obj.setProperty("intersection", intersection); + ScriptValue surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); + obj.setProperty("surfaceNormal", surfaceNormal); + obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); return obj; } -void RayToOverlayIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToOverlayIntersectionResult& value) { - value.intersects = object->property("intersects")->toVariant().toBool(); - ScriptValuePointer overlayIDValue = object->property("overlayID"); +void RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value) { + value.intersects = object.property("intersects").toVariant().toBool(); + ScriptValue overlayIDValue = object.property("overlayID"); quuidFromScriptValue(overlayIDValue, value.overlayID); - value.distance = object->property("distance")->toVariant().toFloat(); - value.face = boxFaceFromString(object->property("face")->toVariant().toString()); + value.distance = object.property("distance").toVariant().toFloat(); + value.face = boxFaceFromString(object.property("face").toVariant().toString()); - ScriptValuePointer intersection = object->property("intersection"); - if (intersection->isValid()) { + ScriptValue intersection = object.property("intersection"); + if (intersection.isValid()) { vec3FromScriptValue(intersection, value.intersection); } - ScriptValuePointer surfaceNormal = object->property("surfaceNormal"); - if (surfaceNormal->isValid()) { + ScriptValue surfaceNormal = object.property("surfaceNormal"); + if (surfaceNormal.isValid()) { vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } - value.extraInfo = object->property("extraInfo")->toVariant().toMap(); + value.extraInfo = object.property("extraInfo").toVariant().toMap(); } bool Overlays::isLoaded(const QUuid& id) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 14f4403a28b..a413eb8b0dc 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include "Overlay.h" @@ -30,8 +30,6 @@ class PickRay; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection}. @@ -55,8 +53,8 @@ class RayToOverlayIntersectionResult { QVariantMap extraInfo; }; Q_DECLARE_METATYPE(RayToOverlayIntersectionResult); -ScriptValuePointer RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value); -void RayToOverlayIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToOverlayIntersectionResult& value); +ScriptValue RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value); +void RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value); class ParabolaToOverlayIntersectionResult { public: @@ -414,8 +412,8 @@ public slots: */ RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false, - const ScriptValuePointer& include = ScriptValuePointer(), - const ScriptValuePointer& discard = ScriptValuePointer(), + const ScriptValue& include = ScriptValue(), + const ScriptValue& discard = ScriptValue(), bool visibleOnly = false, bool collidableOnly = false); diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index db877bf91a8..0b44dfd8dbc 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -18,32 +18,32 @@ const AnimVariant AnimVariant::False = AnimVariant(); -ScriptValuePointer AnimVariantMap::animVariantMapToScriptValue(ScriptEngine* engine, const QStringList& names, bool useNames) const { +ScriptValue AnimVariantMap::animVariantMapToScriptValue(ScriptEngine* engine, const QStringList& names, bool useNames) const { if (QThread::currentThread() != engine->thread()) { qCWarning(animation) << "Cannot create Javacript object from non-script thread" << QThread::currentThread(); Q_ASSERT(false); - return ScriptValuePointer(); + return ScriptValue(); } - ScriptValuePointer target = engine->newObject(); + ScriptValue target = engine->newObject(); auto setOne = [&] (const QString& name, const AnimVariant& value) { switch (value.getType()) { case AnimVariant::Type::Bool: - target->setProperty(name, value.getBool()); + target.setProperty(name, value.getBool()); break; case AnimVariant::Type::Int: - target->setProperty(name, value.getInt()); + target.setProperty(name, value.getInt()); break; case AnimVariant::Type::Float: - target->setProperty(name, value.getFloat()); + target.setProperty(name, value.getFloat()); break; case AnimVariant::Type::String: - target->setProperty(name, value.getString()); + target.setProperty(name, value.getString()); break; case AnimVariant::Type::Vec3: - target->setProperty(name, vec3ToScriptValue(engine, value.getVec3())); + target.setProperty(name, vec3ToScriptValue(engine, value.getVec3())); break; case AnimVariant::Type::Quat: - target->setProperty(name, quatToScriptValue(engine, value.getQuat())); + target.setProperty(name, quatToScriptValue(engine, value.getQuat())); break; default: // Unknown type @@ -56,7 +56,7 @@ ScriptValuePointer AnimVariantMap::animVariantMapToScriptValue(ScriptEngine* eng if (search != _map.end()) { setOne(name, search->second); } else if (_triggers.count(name) == 1) { - target->setProperty(name, true); + target.setProperty(name, true); } // scripts are allowed to request names that do not exist } @@ -74,8 +74,8 @@ void AnimVariantMap::copyVariantsFrom(const AnimVariantMap& other) { } } -void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& source) { - if (QThread::currentThread() != source->engine()->thread()) { +void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValue& source) { + if (QThread::currentThread() != source.engine()->thread()) { qCWarning(animation) << "Cannot examine Javacript object from non-script thread" << QThread::currentThread(); Q_ASSERT(false); return; @@ -84,43 +84,43 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou // Whenever we identify a new outbound type in animVariantMapToScriptValue above, or a new inbound type in the code that follows here, // we would enter it into the dictionary. Then switch on that type here, with the code that follow being executed only if // the type is not known. One problem with that is that there is no checking that two different script use the same name differently. - ScriptValueIteratorPointer property(source->newIterator()); + ScriptValueIteratorPointer property(source.newIterator()); // Note: ScriptValueIterator iterates only over source's own properties. It does not follow the prototype chain. while (property->hasNext()) { property->next(); - ScriptValuePointer value = property->value(); - if (value && value->isBool()) { - set(property->name(), value->toBool()); - } else if (value && value->isString()) { - set(property->name(), value->toString()); - } else if (value && value->isNumber()) { - int asInteger = value->toInt32(); - float asFloat = value->toNumber(); + ScriptValue value = property->value(); + if (value.isBool()) { + set(property->name(), value.toBool()); + } else if (value.isString()) { + set(property->name(), value.toString()); + } else if (value.isNumber()) { + int asInteger = value.toInt32(); + float asFloat = value.toNumber(); if (asInteger == asFloat) { set(property->name(), asInteger); } else { set(property->name(), asFloat); } } else { // Try to get x,y,z and possibly w - if (value && value->isObject()) { - ScriptValuePointer x = value->property("x"); - if (x && x->isNumber()) { - ScriptValuePointer y = value->property("y"); - if (y && y->isNumber()) { - ScriptValuePointer z = value->property("z"); - if (z && z->isNumber()) { - ScriptValuePointer w = value->property("w"); - if (w && w->isNumber()) { - set(property->name(), glm::quat(w->toNumber(), x->toNumber(), y->toNumber(), z->toNumber())); + if (value.isObject()) { + ScriptValue x = value.property("x"); + if (x.isNumber()) { + ScriptValue y = value.property("y"); + if (y.isNumber()) { + ScriptValue z = value.property("z"); + if (z.isNumber()) { + ScriptValue w = value.property("w"); + if (w.isNumber()) { + set(property->name(), glm::quat(w.toNumber(), x.toNumber(), y.toNumber(), z.toNumber())); } else { - set(property->name(), glm::vec3(x->toNumber(), y->toNumber(), z->toNumber())); + set(property->name(), glm::vec3(x.toNumber(), y.toNumber(), z.toNumber())); } continue; // we got either a vector or quaternion object, so don't fall through to warning } } } } - qCWarning(animation) << "Ignoring unrecognized data " << (value ? value->toString() : "(undefined)") << " for animation property " << property->name(); + qCWarning(animation) << "Ignoring unrecognized data " << value.toString() << " for animation property " << property->name(); Q_ASSERT(false); } } diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index 15a0b0d48d7..83cebaa7af1 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -20,11 +20,9 @@ #include #include #include "AnimationLogging.h" -#include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class AnimVariant { public: @@ -233,9 +231,9 @@ class AnimVariantMap { } // Answer a Plain Old Javascript Object (for the given engine) all of our values set as properties. - ScriptValuePointer animVariantMapToScriptValue(ScriptEngine* engine, const QStringList& names, bool useNames) const; + ScriptValue animVariantMapToScriptValue(ScriptEngine* engine, const QStringList& names, bool useNames) const; // Side-effect us with the value of object's own properties. (No inherited properties.) - void animVariantMapFromScriptValue(const ScriptValuePointer& object); + void animVariantMapFromScriptValue(const ScriptValue& object); void copyVariantsFrom(const AnimVariantMap& other); // For stat debugging. @@ -278,7 +276,7 @@ class AnimVariantMap { glm::quat _rigToGeometryRot; }; -typedef std::function AnimVariantResultHandler; +typedef std::function AnimVariantResultHandler; Q_DECLARE_METATYPE(AnimVariantResultHandler); Q_DECLARE_METATYPE(AnimVariantMap) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 409df3f4d64..46dff832c9c 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1586,10 +1586,10 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos } // Allow script to add/remove handlers and report results, from within their thread. -ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList) { // called in script thread +ScriptValue Rig::addAnimationStateHandler(const ScriptValue& handler, const ScriptValue& propertiesList) { // called in script thread // validate argument types - if (handler && handler->isFunction() && (isListOfStrings(propertiesList) || propertiesList->isUndefined() || propertiesList->isNull())) { + if (handler.isFunction() && (isListOfStrings(propertiesList) || propertiesList.isUndefined() || propertiesList.isNull())) { QMutexLocker locker(&_stateMutex); // Find a safe id, even if there are lots of many scripts add and remove handlers repeatedly. while (!_nextStateHandlerId || _stateHandlers.contains(_nextStateHandlerId)) { // 0 is unused, and don't reuse existing after wrap. @@ -1597,28 +1597,28 @@ ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, Scr } StateHandler& data = _stateHandlers[_nextStateHandlerId]; data.function = handler; - data.useNames = propertiesList->isArray(); + data.useNames = propertiesList.isArray(); if (data.useNames) { - data.propertyNames = propertiesList->toVariant().toStringList(); + data.propertyNames = propertiesList.toVariant().toStringList(); } - return handler->engine()->newValue(_nextStateHandlerId); // suitable for giving to removeAnimationStateHandler + return handler.engine()->newValue(_nextStateHandlerId); // suitable for giving to removeAnimationStateHandler } else { qCWarning(animation) << "Rig::addAnimationStateHandler invalid arguments, expected (function, string[])"; - return handler ? handler->engine()->undefinedValue() : ScriptValuePointer(); + return handler.engine() ? handler.engine()->undefinedValue() : ScriptValue(); } } -void Rig::removeAnimationStateHandler(ScriptValuePointer identifier) { // called in script thread +void Rig::removeAnimationStateHandler(const ScriptValue& identifier) { // called in script thread // validate arguments - if (identifier && identifier->isNumber()) { + if (identifier.isNumber()) { QMutexLocker locker(&_stateMutex); - _stateHandlers.remove(identifier->toInt32()); // silently continues if handler not present. 0 is unused + _stateHandlers.remove(identifier.toInt32()); // silently continues if handler not present. 0 is unused } else { qCWarning(animation) << "Rig::removeAnimationStateHandler invalid argument, expected a number"; } } -void Rig::animationStateHandlerResult(int identifier, ScriptValuePointer result) { // called synchronously from script +void Rig::animationStateHandlerResult(int identifier, const ScriptValue& result) { // called synchronously from script QMutexLocker locker(&_stateMutex); auto found = _stateHandlers.find(identifier); if (found == _stateHandlers.end()) { @@ -1637,9 +1637,9 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh // call out: int identifier = data.key(); StateHandler& value = data.value(); - ScriptValuePointer& function = value.function; + ScriptValue& function = value.function; int rigId = _rigId; - auto handleResult = [rigId, identifier](ScriptValuePointer result) { // called in script thread to get the result back to us. + auto handleResult = [rigId, identifier](const ScriptValue& result) { // called in script thread to get the result back to us. // Hold the rigRegistryMutex to ensure thread-safe access to the rigRegistry, but // also to prevent the rig from being deleted while this lambda is being executed. std::lock_guard guard(rigRegistryMutex); @@ -1658,20 +1658,20 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh // Copies of AnimVariantMap do copy the underlying map, so this will correctly capture // the state of _animVars and allow continued changes to _animVars in this thread without conflict. const AnimVariantMap& animVars = _animVars; - ScriptEnginePointer engine = function->engine(); + ScriptEnginePointer engine = function.engine(); const QStringList& names = value.propertyNames; bool useNames = value.useNames; QMetaObject::invokeMethod( engine->manager(), [function, animVars, names, useNames, handleResult, engine] { - ScriptValuePointer javascriptParameters = animVars.animVariantMapToScriptValue(engine.get(), names, useNames); + ScriptValue javascriptParameters = animVars.animVariantMapToScriptValue(engine.get(), names, useNames); ScriptValueList callingArguments; callingArguments << javascriptParameters; - ScriptValuePointer result = function->call(ScriptValuePointer(), callingArguments); + ScriptValue result = function.call(ScriptValue(), callingArguments); // validate result from callback function. - if (result->isValid() && result->isObject()) { + if (result.isValid() && result.isObject()) { handleResult(result); } else { qCWarning(animation) << "Rig::updateAnimationStateHandlers invalid return argument from " diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index f2f672df35d..9b7704bc159 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include "AnimNode.h" #include "AnimNodeLoader.h" @@ -30,8 +30,6 @@ class Rig; class AnimInverseKinematics; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; // Rig instances are reentrant. // However only specific methods thread-safe. Noted below. @@ -42,7 +40,7 @@ class Rig : public QObject { struct StateHandler { AnimVariantMap results; QStringList propertyNames; - ScriptValuePointer function; + ScriptValue function; bool useNames; }; @@ -207,9 +205,9 @@ class Rig : public QObject { AnimNode::ConstPointer getAnimNode() const { return _animNode; } AnimNode::ConstPointer findAnimNodeByName(const QString& name) const; AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; } - ScriptValuePointer addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList); - void removeAnimationStateHandler(ScriptValuePointer handler); - void animationStateHandlerResult(int identifier, ScriptValuePointer result); + ScriptValue addAnimationStateHandler(const ScriptValue& handler, const ScriptValue& propertiesList); + void removeAnimationStateHandler(const ScriptValue& handler); + void animationStateHandlerResult(int identifier, const ScriptValue& result); // rig space bool getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const; diff --git a/libraries/audio-client/CMakeLists.txt b/libraries/audio-client/CMakeLists.txt index 6b88292dd4e..03a9fc087ba 100644 --- a/libraries/audio-client/CMakeLists.txt +++ b/libraries/audio-client/CMakeLists.txt @@ -6,6 +6,7 @@ setup_hifi_library(Network Multimedia ${PLATFORM_QT_COMPONENTS}) link_hifi_libraries(audio plugins) include_hifi_library_headers(shared) include_hifi_library_headers(networking) +include_hifi_library_headers(script-engine) if (ANDROID) else () diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 4fb7d939838..8edddd9092e 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -18,8 +18,8 @@ STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { auto scriptEngine = manager->engine().data(); - ScriptValuePointer audioEffectOptionsConstructorValue = scriptEngine->newFunction(AudioEffectOptions::constructor); - scriptEngine->globalObject()->setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); + ScriptValue audioEffectOptionsConstructorValue = scriptEngine->newFunction(AudioEffectOptions::constructor); + scriptEngine->globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); }); static const QString BANDWIDTH_HANDLE = "bandwidth"; @@ -66,8 +66,8 @@ static const float LATE_MIX_LEFT_DEFAULT = 90.0f; static const float LATE_MIX_RIGHT_DEFAULT = 90.0f; static const float WET_DRY_MIX_DEFAULT = 50.0f; -static void setOption(ScriptValuePointer arguments, const QString name, float defaultValue, float& variable) { - variable = arguments && arguments->property(name)->isNumber() ? (float)arguments->property(name)->toNumber() : defaultValue; +static void setOption(const ScriptValue& arguments, const QString name, float defaultValue, float& variable) { + variable = arguments.property(name).isNumber() ? (float)arguments.property(name).toNumber() : defaultValue; } /*@jsdoc @@ -95,7 +95,7 @@ static void setOption(ScriptValuePointer arguments, const QString name, float de * @property {number} lateMixRight=90 - The apparent distance of the source (percent) in the reverb tail. * @property {number} wetDryMix=50 - Adjusts the wet/dry ratio, from completely dry (0%) to completely wet (100%). */ -AudioEffectOptions::AudioEffectOptions(ScriptValuePointer arguments) { +AudioEffectOptions::AudioEffectOptions(const ScriptValue& arguments) { setOption(arguments, BANDWIDTH_HANDLE, BANDWIDTH_DEFAULT, _bandwidth); setOption(arguments, PRE_DELAY_HANDLE, PRE_DELAY_DEFAULT, _preDelay); setOption(arguments, LATE_DELAY_HANDLE, LATE_DELAY_DEFAULT, _lateDelay); @@ -149,6 +149,6 @@ AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &othe return *this; } -ScriptValuePointer AudioEffectOptions::constructor(ScriptContext* context, ScriptEngine* engine) { +ScriptValue AudioEffectOptions::constructor(ScriptContext* context, ScriptEngine* engine) { return engine->newQObject(new AudioEffectOptions(context->argument(0))); } diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index 4f02a765f6a..7ac2c83a248 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -12,12 +12,10 @@ #define hifi_AudioEffectOptions_h #include -#include +#include class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * Audio effect options used by the {@link Audio} API. @@ -82,11 +80,11 @@ class AudioEffectOptions : public QObject { Q_PROPERTY(float wetDryMix READ getWetDryMix WRITE setWetDryMix) public: - AudioEffectOptions(ScriptValuePointer arguments = ScriptValuePointer()); + AudioEffectOptions(const ScriptValue& arguments = ScriptValue()); AudioEffectOptions(const AudioEffectOptions &other); AudioEffectOptions& operator=(const AudioEffectOptions &other); - static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine); + static ScriptValue constructor(ScriptContext* context, ScriptEngine* engine); float getBandwidth() const { return _bandwidth; } void setBandwidth(float bandwidth) { _bandwidth = bandwidth; } diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 27ca80687fa..94597e4757f 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -32,18 +32,18 @@ AudioInjectorOptions::AudioInjectorOptions() : { } -ScriptValuePointer injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInjectorOptions& injectorOptions) { - ScriptValuePointer obj = engine->newObject(); +ScriptValue injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInjectorOptions& injectorOptions) { + ScriptValue obj = engine->newObject(); if (injectorOptions.positionSet) { - obj->setProperty("position", vec3ToScriptValue(engine, injectorOptions.position)); + obj.setProperty("position", vec3ToScriptValue(engine, injectorOptions.position)); } - obj->setProperty("volume", injectorOptions.volume); - obj->setProperty("loop", injectorOptions.loop); - obj->setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); - obj->setProperty("ignorePenumbra", injectorOptions.ignorePenumbra); - obj->setProperty("localOnly", injectorOptions.localOnly); - obj->setProperty("secondOffset", injectorOptions.secondOffset); - obj->setProperty("pitch", injectorOptions.pitch); + obj.setProperty("volume", injectorOptions.volume); + obj.setProperty("loop", injectorOptions.loop); + obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); + obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra); + obj.setProperty("localOnly", injectorOptions.localOnly); + obj.setProperty("secondOffset", injectorOptions.secondOffset); + obj.setProperty("pitch", injectorOptions.pitch); return obj; } @@ -66,8 +66,8 @@ ScriptValuePointer injectorOptionsToScriptValue(ScriptEngine* engine, const Audi * @property {boolean} ignorePenumbra=false -

Deprecated: This property is deprecated and will be * removed.

*/ -void injectorOptionsFromScriptValue(const ScriptValuePointer& object, AudioInjectorOptions& injectorOptions) { - if (!object || !object->isObject()) { +void injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions) { + if (!object.isObject()) { qWarning() << "Audio injector options is not an object."; return; } @@ -77,48 +77,48 @@ void injectorOptionsFromScriptValue(const ScriptValuePointer& object, AudioInjec } injectorOptions.positionSet = false; - ScriptValueIteratorPointer it(object->newIterator()); + ScriptValueIteratorPointer it(object.newIterator()); while (it->hasNext()) { it->next(); if (it->name() == "position") { - vec3FromScriptValue(object->property("position"), injectorOptions.position); + vec3FromScriptValue(object.property("position"), injectorOptions.position); injectorOptions.positionSet = true; } else if (it->name() == "orientation") { - quatFromScriptValue(object->property("orientation"), injectorOptions.orientation); + quatFromScriptValue(object.property("orientation"), injectorOptions.orientation); } else if (it->name() == "volume") { - if (it->value()->isNumber()) { - injectorOptions.volume = it->value()->toNumber(); + if (it->value().isNumber()) { + injectorOptions.volume = it->value().toNumber(); } else { qCWarning(audio) << "Audio injector options: volume is not a number"; } } else if (it->name() == "loop") { - if (it->value()->isBool()) { - injectorOptions.loop = it->value()->toBool(); + if (it->value().isBool()) { + injectorOptions.loop = it->value().toBool(); } else { qCWarning(audio) << "Audio injector options: loop is not a boolean"; } } else if (it->name() == "ignorePenumbra") { - if (it->value()->isBool()) { - injectorOptions.ignorePenumbra = it->value()->toBool(); + if (it->value().isBool()) { + injectorOptions.ignorePenumbra = it->value().toBool(); } else { qCWarning(audio) << "Audio injector options: ignorePenumbra is not a boolean"; } } else if (it->name() == "localOnly") { - if (it->value()->isBool()) { - injectorOptions.localOnly = it->value()->toBool(); + if (it->value().isBool()) { + injectorOptions.localOnly = it->value().toBool(); } else { qCWarning(audio) << "Audio injector options: localOnly is not a boolean"; } } else if (it->name() == "secondOffset") { - if (it->value()->isNumber()) { - injectorOptions.secondOffset = it->value()->toNumber(); + if (it->value().isNumber()) { + injectorOptions.secondOffset = it->value().toNumber(); } else { qCWarning(audio) << "Audio injector options: secondOffset is not a number"; } } else if (it->name() == "pitch") { - if (it->value()->isNumber()) { - injectorOptions.pitch = it->value()->toNumber(); + if (it->value().isNumber()) { + injectorOptions.pitch = it->value().toNumber(); } else { qCWarning(audio) << "Audio injector options: pitch is not a number"; } diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index 3605bc2a068..0dd3ab1cb14 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -14,11 +14,9 @@ #include #include -#include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class AudioInjectorOptions { public: @@ -38,7 +36,7 @@ class AudioInjectorOptions { Q_DECLARE_METATYPE(AudioInjectorOptions); -ScriptValuePointer injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInjectorOptions& injectorOptions); -void injectorOptionsFromScriptValue(const ScriptValuePointer& object, AudioInjectorOptions& injectorOptions); +ScriptValue injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInjectorOptions& injectorOptions); +void injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions); #endif // hifi_AudioInjectorOptions_h diff --git a/libraries/audio/src/ScriptAudioInjector.cpp b/libraries/audio/src/ScriptAudioInjector.cpp index 67a761c149a..d50bf6f163c 100644 --- a/libraries/audio/src/ScriptAudioInjector.cpp +++ b/libraries/audio/src/ScriptAudioInjector.cpp @@ -23,7 +23,7 @@ STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { scriptRegisterMetaType(scriptEngine, injectorToScriptValue, injectorFromScriptValue); }); -ScriptValuePointer injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in) { +ScriptValue injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in) { // The AudioScriptingInterface::playSound method can return null, so we need to account for that. if (!in) { return engine->nullValue(); @@ -32,8 +32,8 @@ ScriptValuePointer injectorToScriptValue(ScriptEngine* engine, ScriptAudioInject return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void injectorFromScriptValue(const ScriptValuePointer& object, ScriptAudioInjector*& out) { - out = qobject_cast(object->toQObject()); +void injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out) { + out = qobject_cast(object.toQObject()); } ScriptAudioInjector::ScriptAudioInjector(const AudioInjectorPointer& injector) : diff --git a/libraries/audio/src/ScriptAudioInjector.h b/libraries/audio/src/ScriptAudioInjector.h index 30be70e7acb..7a55341756c 100644 --- a/libraries/audio/src/ScriptAudioInjector.h +++ b/libraries/audio/src/ScriptAudioInjector.h @@ -16,13 +16,11 @@ #define hifi_ScriptAudioInjector_h #include -#include +#include #include "AudioInjectorManager.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * Plays or "injects" the content of an audio file. @@ -148,13 +146,13 @@ public slots: private: QWeakPointer _injector; - friend ScriptValuePointer injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in); + friend ScriptValue injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in); }; Q_DECLARE_METATYPE(ScriptAudioInjector*) -ScriptValuePointer injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in); -void injectorFromScriptValue(const ScriptValuePointer& object, ScriptAudioInjector*& out); +ScriptValue injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in); +void injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out); #endif // hifi_ScriptAudioInjector_h diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index c6b68112285..a880da037cf 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -424,12 +424,12 @@ SoundProcessor::AudioProperties SoundProcessor::interpretAsMP3(const QByteArray& } -ScriptValuePointer soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in) { +ScriptValue soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in) { return engine->newQObject(new SoundScriptingInterface(in), ScriptEngine::ScriptOwnership); } -void soundSharedPointerFromScriptValue(const ScriptValuePointer& object, SharedSoundPointer& out) { - if (auto soundInterface = qobject_cast(object->toQObject())) { +void soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out) { + if (auto soundInterface = qobject_cast(object.toQObject())) { out = soundInterface->getSound(); } } diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 0ea4079d7b0..307a5d903a1 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -18,14 +18,13 @@ #include #include +#include #include "AudioConstants.h" class AudioData; class ScriptEngine; -class ScriptValue; using AudioDataPointer = std::shared_ptr; -using ScriptValuePointer = QSharedPointer; Q_DECLARE_METATYPE(AudioDataPointer); @@ -171,7 +170,7 @@ class SoundScriptingInterface : public QObject { }; Q_DECLARE_METATYPE(SharedSoundPointer) -ScriptValuePointer soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in); -void soundSharedPointerFromScriptValue(const ScriptValuePointer& object, SharedSoundPointer& out); +ScriptValue soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in); +void soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out); #endif // hifi_Sound_h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1342c89fb60..184f1bf7048 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -3153,40 +3153,40 @@ glm::mat4 AvatarData::getControllerRightHandMatrix() const { * @property {SubmeshIntersection} extraInfo - Extra information on the mesh intersected if mesh was picked against, * {} if it wasn't. */ -ScriptValuePointer RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, const RayToAvatarIntersectionResult& value) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("intersects", value.intersects); - ScriptValuePointer avatarIDValue = quuidToScriptValue(engine, value.avatarID); - obj->setProperty("avatarID", avatarIDValue); - obj->setProperty("distance", value.distance); - obj->setProperty("face", boxFaceToString(value.face)); - ScriptValuePointer intersection = vec3ToScriptValue(engine, value.intersection); - - obj->setProperty("intersection", intersection); - ScriptValuePointer surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); - obj->setProperty("surfaceNormal", surfaceNormal); - obj->setProperty("jointIndex", value.jointIndex); - obj->setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); +ScriptValue RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, const RayToAvatarIntersectionResult& value) { + ScriptValue obj = engine->newObject(); + obj.setProperty("intersects", value.intersects); + ScriptValue avatarIDValue = quuidToScriptValue(engine, value.avatarID); + obj.setProperty("avatarID", avatarIDValue); + obj.setProperty("distance", value.distance); + obj.setProperty("face", boxFaceToString(value.face)); + ScriptValue intersection = vec3ToScriptValue(engine, value.intersection); + + obj.setProperty("intersection", intersection); + ScriptValue surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); + obj.setProperty("surfaceNormal", surfaceNormal); + obj.setProperty("jointIndex", value.jointIndex); + obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); return obj; } -void RayToAvatarIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToAvatarIntersectionResult& value) { - value.intersects = object->property("intersects")->toVariant().toBool(); - ScriptValuePointer avatarIDValue = object->property("avatarID"); +void RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& value) { + value.intersects = object.property("intersects").toVariant().toBool(); + ScriptValue avatarIDValue = object.property("avatarID"); quuidFromScriptValue(avatarIDValue, value.avatarID); - value.distance = object->property("distance")->toVariant().toFloat(); - value.face = boxFaceFromString(object->property("face")->toVariant().toString()); + value.distance = object.property("distance").toVariant().toFloat(); + value.face = boxFaceFromString(object.property("face").toVariant().toString()); - ScriptValuePointer intersection = object->property("intersection"); - if (intersection && intersection->isValid()) { + ScriptValue intersection = object.property("intersection"); + if (intersection.isValid()) { vec3FromScriptValue(intersection, value.intersection); } - ScriptValuePointer surfaceNormal = object->property("surfaceNormal"); - if (surfaceNormal && surfaceNormal->isValid()) { + ScriptValue surfaceNormal = object.property("surfaceNormal"); + if (surfaceNormal.isValid()) { vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } - value.jointIndex = object->property("jointIndex")->toInt32(); - value.extraInfo = object->property("extraInfo")->toVariant().toMap(); + value.jointIndex = object.property("jointIndex").toInt32(); + value.extraInfo = object.property("extraInfo").toVariant().toMap(); } // these coefficients can be changed via JS for experimental tuning @@ -3199,8 +3199,8 @@ float AvatarData::_avatarSortCoefficientAge { 1.0f }; * An object with the UUIDs of avatar entities as keys and avatar entity properties objects as values. * @typedef {Object.} AvatarEntityMap */ -ScriptValuePointer AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntityMap& value) { - ScriptValuePointer obj = engine->newObject(); +ScriptValue AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntityMap& value) { + ScriptValue obj = engine->newObject(); for (auto entityID : value.keys()) { QByteArray entityProperties = value.value(entityID); QJsonDocument jsonEntityProperties = QJsonDocument::fromBinaryData(entityProperties); @@ -3210,22 +3210,22 @@ ScriptValuePointer AvatarEntityMapToScriptValue(ScriptEngine* engine, const Avat QVariant variantEntityProperties = jsonEntityProperties.toVariant(); QVariantMap entityPropertiesMap = variantEntityProperties.toMap(); - ScriptValuePointer scriptEntityProperties = variantMapToScriptValue(entityPropertiesMap, *engine); + ScriptValue scriptEntityProperties = variantMapToScriptValue(entityPropertiesMap, *engine); QString key = entityID.toString(); - obj->setProperty(key, scriptEntityProperties); + obj.setProperty(key, scriptEntityProperties); } return obj; } -void AvatarEntityMapFromScriptValue(const ScriptValuePointer& object, AvatarEntityMap& value) { - ScriptValueIteratorPointer itr(object->newIterator()); +void AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value) { + ScriptValueIteratorPointer itr(object.newIterator()); while (itr->hasNext()) { itr->next(); QUuid EntityID = QUuid(itr->name()); - ScriptValuePointer scriptEntityProperties = itr->value(); - QVariant variantEntityProperties = scriptEntityProperties->toVariant(); + ScriptValue scriptEntityProperties = itr->value(); + QVariant variantEntityProperties = scriptEntityProperties.toVariant(); QJsonDocument jsonEntityProperties = QJsonDocument::fromVariant(variantEntityProperties); QByteArray binaryEntityProperties = jsonEntityProperties.toBinaryData(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 46abb9bcd71..bb1c1ddca59 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -33,7 +33,6 @@ #include #include #include -#include #include #include @@ -50,6 +49,7 @@ #include #include #include "Scriptable.h" +#include #include "AABox.h" #include "AvatarTraits.h" @@ -57,8 +57,6 @@ #include "PathUtils.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; @@ -1973,8 +1971,8 @@ class RayToAvatarIntersectionResult { QVariantMap extraInfo; }; Q_DECLARE_METATYPE(RayToAvatarIntersectionResult) -ScriptValuePointer RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, const RayToAvatarIntersectionResult& results); -void RayToAvatarIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToAvatarIntersectionResult& results); +ScriptValue RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, const RayToAvatarIntersectionResult& results); +void RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& results); // No JSDoc because it's not provided as a type to the script engine. class ParabolaToAvatarIntersectionResult { @@ -1991,8 +1989,8 @@ class ParabolaToAvatarIntersectionResult { Q_DECLARE_METATYPE(AvatarEntityMap) -ScriptValuePointer AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntityMap& value); -void AvatarEntityMapFromScriptValue(const ScriptValuePointer& object, AvatarEntityMap& value); +ScriptValue AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntityMap& value); +void AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value); // faux joint indexes (-1 means invalid) const int NO_JOINT_INDEX = 65535; // -1 diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index 6f322190c09..5b33f53cd56 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -14,11 +14,11 @@ #include #include -ScriptValuePointer avatarDataToScriptValue(ScriptEngine* engine, ScriptAvatarData* const& in) { +ScriptValue avatarDataToScriptValue(ScriptEngine* engine, ScriptAvatarData* const& in) { return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void avatarDataFromScriptValue(const ScriptValuePointer& object, ScriptAvatarData*& out) { +void avatarDataFromScriptValue(const ScriptValue& object, ScriptAvatarData*& out) { // This is not implemented because there are no slots/properties that take an AvatarSharedPointer from a script assert(false); out = nullptr; diff --git a/libraries/baking/src/MaterialBaker.cpp b/libraries/baking/src/MaterialBaker.cpp index d5f1d652c51..7922137a056 100644 --- a/libraries/baking/src/MaterialBaker.cpp +++ b/libraries/baking/src/MaterialBaker.cpp @@ -212,13 +212,13 @@ void MaterialBaker::outputMaterial() { if (_materialResource->parsedMaterials.networkMaterials.size() == 1) { auto networkMaterial = _materialResource->parsedMaterials.networkMaterials.begin(); auto scriptableMaterial = scriptable::ScriptableMaterial(networkMaterial->second); - QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(_scriptEngine.data(), scriptableMaterial)->toVariant(); + QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(_scriptEngine.data(), scriptableMaterial).toVariant(); json.insert("materials", QJsonDocument::fromVariant(materialVariant).object()); } else { QJsonArray materialArray; for (auto networkMaterial : _materialResource->parsedMaterials.networkMaterials) { auto scriptableMaterial = scriptable::ScriptableMaterial(networkMaterial.second); - QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(_scriptEngine.data(), scriptableMaterial)->toVariant(); + QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(_scriptEngine.data(), scriptableMaterial).toVariant(); materialArray.append(QJsonDocument::fromVariant(materialVariant).object()); } json.insert("materials", materialArray); diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index ec58a6443e7..bfb6f6afc42 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -40,25 +40,25 @@ namespace controller { * @property {Vec3} angularVelocity - Angular velocity in rad/s. * @property {boolean} valid - true if the pose is valid, otherwise false. */ - ScriptValuePointer Pose::toScriptValue(ScriptEngine* engine, const Pose& pose) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("translation", vec3ToScriptValue(engine, pose.translation)); - obj->setProperty("rotation", quatToScriptValue(engine, pose.rotation)); - obj->setProperty("velocity", vec3ToScriptValue(engine, pose.velocity)); - obj->setProperty("angularVelocity", vec3ToScriptValue(engine, pose.angularVelocity)); - obj->setProperty("valid", pose.valid); + ScriptValue Pose::toScriptValue(ScriptEngine* engine, const Pose& pose) { + ScriptValue obj = engine->newObject(); + obj.setProperty("translation", vec3ToScriptValue(engine, pose.translation)); + obj.setProperty("rotation", quatToScriptValue(engine, pose.rotation)); + obj.setProperty("velocity", vec3ToScriptValue(engine, pose.velocity)); + obj.setProperty("angularVelocity", vec3ToScriptValue(engine, pose.angularVelocity)); + obj.setProperty("valid", pose.valid); return obj; } - void Pose::fromScriptValue(const ScriptValuePointer& object, Pose& pose) { - auto translation = object->property("translation"); - auto rotation = object->property("rotation"); - auto velocity = object->property("velocity"); - auto angularVelocity = object->property("angularVelocity"); - if (translation->isValid() && - rotation->isValid() && - velocity->isValid() && - angularVelocity->isValid()) { + void Pose::fromScriptValue(const ScriptValue& object, Pose& pose) { + auto translation = object.property("translation"); + auto rotation = object.property("rotation"); + auto velocity = object.property("velocity"); + auto angularVelocity = object.property("angularVelocity"); + if (translation.isValid() && + rotation.isValid() && + velocity.isValid() && + angularVelocity.isValid()) { vec3FromScriptValue(translation, pose.translation); quatFromScriptValue(rotation, pose.rotation); vec3FromScriptValue(velocity, pose.velocity); diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h index 0dff0293d15..7a71c7c5bbc 100644 --- a/libraries/controllers/src/controllers/Pose.h +++ b/libraries/controllers/src/controllers/Pose.h @@ -10,11 +10,9 @@ #pragma once #ifndef hifi_controllers_Pose_h #define hifi_controllers_Pose_h -#include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; #include @@ -46,8 +44,8 @@ namespace controller { Pose transform(const glm::mat4& mat) const; Pose postTransform(const glm::mat4& mat) const; - static ScriptValuePointer toScriptValue(ScriptEngine* engine, const Pose& event); - static void fromScriptValue(const ScriptValuePointer& object, Pose& event); + static ScriptValue toScriptValue(ScriptEngine* engine, const Pose& event); + static void fromScriptValue(const ScriptValue& object, Pose& event); }; } diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index 396e7cb5d42..9e538b999b7 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -33,12 +33,12 @@ Q_DECLARE_METATYPE(controller::InputController*) //static int inputControllerPointerId = qRegisterMetaType(); -ScriptValuePointer inputControllerToScriptValue(ScriptEngine* engine, controller::InputController* const& in) { +ScriptValue inputControllerToScriptValue(ScriptEngine* engine, controller::InputController* const& in) { return engine->newQObject(in, ScriptEngine::QtOwnership); } -void inputControllerFromScriptValue(const ScriptValuePointer& object, controller::InputController*& out) { - out = qobject_cast(object->toQObject()); +void inputControllerFromScriptValue(const ScriptValue& object, controller::InputController*& out) { + out = qobject_cast(object.toQObject()); } STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 865149f8c38..8e3b7682391 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -392,58 +392,58 @@ int inputPairMetaTypeId = qRegisterMetaType(); int poseMetaTypeId = qRegisterMetaType("Pose"); int handMetaTypeId = qRegisterMetaType(); -ScriptValuePointer inputToScriptValue(ScriptEngine* engine, const Input& input); -void inputFromScriptValue(const ScriptValuePointer& object, Input& input); -ScriptValuePointer actionToScriptValue(ScriptEngine* engine, const Action& action); -void actionFromScriptValue(const ScriptValuePointer& object, Action& action); -ScriptValuePointer inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair); -void inputPairFromScriptValue(const ScriptValuePointer& object, Input::NamedPair& inputPair); -ScriptValuePointer handToScriptValue(ScriptEngine* engine, const controller::Hand& hand); -void handFromScriptValue(const ScriptValuePointer& object, controller::Hand& hand); - -ScriptValuePointer inputToScriptValue(ScriptEngine* engine, const Input& input) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("device", input.getDevice()); - obj->setProperty("channel", input.getChannel()); - obj->setProperty("type", (unsigned short)input.getType()); - obj->setProperty("id", input.getID()); +ScriptValue inputToScriptValue(ScriptEngine* engine, const Input& input); +void inputFromScriptValue(const ScriptValue& object, Input& input); +ScriptValue actionToScriptValue(ScriptEngine* engine, const Action& action); +void actionFromScriptValue(const ScriptValue& object, Action& action); +ScriptValue inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair); +void inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair); +ScriptValue handToScriptValue(ScriptEngine* engine, const controller::Hand& hand); +void handFromScriptValue(const ScriptValue& object, controller::Hand& hand); + +ScriptValue inputToScriptValue(ScriptEngine* engine, const Input& input) { + ScriptValue obj = engine->newObject(); + obj.setProperty("device", input.getDevice()); + obj.setProperty("channel", input.getChannel()); + obj.setProperty("type", (unsigned short)input.getType()); + obj.setProperty("id", input.getID()); return obj; } -void inputFromScriptValue(const ScriptValuePointer& object, Input& input) { - input.id = object->property("id")->toInt32(); +void inputFromScriptValue(const ScriptValue& object, Input& input) { + input.id = object.property("id").toInt32(); } -ScriptValuePointer actionToScriptValue(ScriptEngine* engine, const Action& action) { - ScriptValuePointer obj = engine->newObject(); +ScriptValue actionToScriptValue(ScriptEngine* engine, const Action& action) { + ScriptValue obj = engine->newObject(); auto userInputMapper = DependencyManager::get(); - obj->setProperty("action", (int)action); - obj->setProperty("actionName", userInputMapper->getActionName(action)); + obj.setProperty("action", (int)action); + obj.setProperty("actionName", userInputMapper->getActionName(action)); return obj; } -void actionFromScriptValue(const ScriptValuePointer& object, Action& action) { - action = Action(object->property("action")->toVariant().toInt()); +void actionFromScriptValue(const ScriptValue& object, Action& action) { + action = Action(object.property("action").toVariant().toInt()); } -ScriptValuePointer inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("input", inputToScriptValue(engine, inputPair.first)); - obj->setProperty("inputName", inputPair.second); +ScriptValue inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair) { + ScriptValue obj = engine->newObject(); + obj.setProperty("input", inputToScriptValue(engine, inputPair.first)); + obj.setProperty("inputName", inputPair.second); return obj; } -void inputPairFromScriptValue(const ScriptValuePointer& object, Input::NamedPair& inputPair) { - inputFromScriptValue(object->property("input"), inputPair.first); - inputPair.second = QString(object->property("inputName")->toVariant().toString()); +void inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair) { + inputFromScriptValue(object.property("input"), inputPair.first); + inputPair.second = QString(object.property("inputName").toVariant().toString()); } -ScriptValuePointer handToScriptValue(ScriptEngine* engine, const controller::Hand& hand) { +ScriptValue handToScriptValue(ScriptEngine* engine, const controller::Hand& hand) { return engine->newValue((int)hand); } -void handFromScriptValue(const ScriptValuePointer& object, controller::Hand& hand) { - hand = Hand(object->toVariant().toInt()); +void handFromScriptValue(const ScriptValue& object, controller::Hand& hand) { + hand = Hand(object.toVariant().toInt()); } void UserInputMapper::registerControllerTypes(ScriptEngine* engine) { @@ -662,21 +662,21 @@ Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) { return Endpoint::Pointer(); } -Endpoint::Pointer UserInputMapper::endpointFor(const ScriptValuePointer& endpoint) { - if (endpoint->isNumber()) { - return endpointFor(Input(endpoint->toInt32())); +Endpoint::Pointer UserInputMapper::endpointFor(const ScriptValue& endpoint) { + if (endpoint.isNumber()) { + return endpointFor(Input(endpoint.toInt32())); } - if (endpoint->isFunction()) { + if (endpoint.isFunction()) { auto result = std::make_shared(endpoint); return result; } - if (endpoint->isArray()) { - int length = endpoint->property("length")->toInteger(); + if (endpoint.isArray()) { + int length = endpoint.property("length").toInteger(); Endpoint::List children; for (int i = 0; i < length; i++) { - ScriptValuePointer arrayItem = endpoint->property(i); + ScriptValue arrayItem = endpoint.property(i); Endpoint::Pointer destination = endpointFor(arrayItem); if (!destination) { return Endpoint::Pointer(); @@ -687,7 +687,7 @@ Endpoint::Pointer UserInputMapper::endpointFor(const ScriptValuePointer& endpoin } - qWarning() << "Unsupported input type " << endpoint->toString(); + qWarning() << "Unsupported input type " << endpoint.toString(); return Endpoint::Pointer(); } @@ -887,12 +887,12 @@ Conditional::Pointer UserInputMapper::conditionalFor(const QJSValue& condition) return Conditional::Pointer(); } -Conditional::Pointer UserInputMapper::conditionalFor(const ScriptValuePointer& condition) { - if (condition->isArray()) { - int length = condition->property("length")->toInteger(); +Conditional::Pointer UserInputMapper::conditionalFor(const ScriptValue& condition) { + if (condition.isArray()) { + int length = condition.property("length").toInteger(); Conditional::List children; for (int i = 0; i < length; i++) { - Conditional::Pointer destination = conditionalFor(condition->property(i)); + Conditional::Pointer destination = conditionalFor(condition.property(i)); if (!destination) { return Conditional::Pointer(); } @@ -901,15 +901,15 @@ Conditional::Pointer UserInputMapper::conditionalFor(const ScriptValuePointer& c return std::make_shared(children); } - if (condition->isNumber()) { - return conditionalFor(Input(condition->toInt32())); + if (condition.isNumber()) { + return conditionalFor(Input(condition.toInt32())); } - if (condition->isFunction()) { + if (condition.isFunction()) { return std::make_shared(condition); } - qWarning() << "Unsupported conditional type " << condition->toString(); + qWarning() << "Unsupported conditional type " << condition.toString(); return Conditional::Pointer(); } diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index 6e67ca22ee4..3fcce461c01 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -16,7 +16,6 @@ #include #include #include -#include #include @@ -34,7 +33,6 @@ class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; namespace controller { @@ -168,10 +166,10 @@ namespace controller { void enableMapping(const MappingPointer& mapping); void disableMapping(const MappingPointer& mapping); EndpointPointer endpointFor(const QJSValue& endpoint); - EndpointPointer endpointFor(const ScriptValuePointer& endpoint); + EndpointPointer endpointFor(const ScriptValue& endpoint); EndpointPointer compositeEndpointFor(EndpointPointer first, EndpointPointer second); ConditionalPointer conditionalFor(const QJSValue& endpoint); - ConditionalPointer conditionalFor(const ScriptValuePointer& endpoint); + ConditionalPointer conditionalFor(const ScriptValue& endpoint); ConditionalPointer conditionalFor(const Input& endpoint) const; MappingPointer parseMapping(const QJsonValue& json); diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp index d82aece9e94..6452dd0d130 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp @@ -27,8 +27,8 @@ QObject* MappingBuilderProxy::fromQml(const QJSValue& source) { return from(sourceEndpoint); } -QObject* MappingBuilderProxy::from(const ScriptValuePointer& source) { - qCDebug(controllers) << "Creating new Route builder proxy from " << source->toString(); +QObject* MappingBuilderProxy::from(const ScriptValue& source) { + qCDebug(controllers) << "Creating new Route builder proxy from " << source.toString(); auto sourceEndpoint = _parent.endpointFor(source); return from(sourceEndpoint); } @@ -50,7 +50,7 @@ QObject* MappingBuilderProxy::makeAxisQml(const QJSValue& source1, const QJSValu return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint)); } -QObject* MappingBuilderProxy::makeAxis(const ScriptValuePointer& source1, const ScriptValuePointer& source2) { +QObject* MappingBuilderProxy::makeAxis(const ScriptValue& source1, const ScriptValue& source2) { auto source1Endpoint = _parent.endpointFor(source1); auto source2Endpoint = _parent.endpointFor(source2); return from(_parent.compositeEndpointFor(source1Endpoint, source2Endpoint)); diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h index bb528666b7c..b496f78361b 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -11,7 +11,6 @@ #include #include -#include #include "Mapping.h" #include "Endpoint.h" @@ -19,7 +18,6 @@ class QJSValue; class QJsonValue; class ScriptValue; -using ScriptValuePointer = QSharedPointer; namespace controller { @@ -167,7 +165,7 @@ class MappingBuilderProxy : public QObject { * of the route data. If a function, it must return a number or a {@link Pose} value as the route data. * @returns {RouteObject} A route ready for mapping to an action or function using {@link RouteObject} methods. */ - Q_INVOKABLE QObject* from(const ScriptValuePointer& source); + Q_INVOKABLE QObject* from(const ScriptValue& source); /*@jsdoc * Creates a new {@link RouteObject} from two numeric {@link Controller.Hardware} outputs, one applied in the negative @@ -189,7 +187,7 @@ class MappingBuilderProxy : public QObject { * Controller.disableMapping(MAPPING_NAME); * }); */ - Q_INVOKABLE QObject* makeAxis(const ScriptValuePointer& source1, const ScriptValuePointer& source2); + Q_INVOKABLE QObject* makeAxis(const ScriptValue& source1, const ScriptValue& source2); /*@jsdoc * Enables or disables the mapping. When enabled, the routes in the mapping take effect. diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp index 49308c6e412..3330d6eca44 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp @@ -44,8 +44,8 @@ void RouteBuilderProxy::toQml(const QJSValue& destination) { return to(destinationEndpoint); } -void RouteBuilderProxy::to(const ScriptValuePointer& destination) { - qCDebug(controllers) << "Completing route " << destination->toString(); +void RouteBuilderProxy::to(const ScriptValue& destination) { + qCDebug(controllers) << "Completing route " << destination.toString(); auto destinationEndpoint = _parent.endpointFor(destination); return to(destinationEndpoint); } @@ -66,7 +66,7 @@ QObject* RouteBuilderProxy::peek(bool enable) { return this; } -QObject* RouteBuilderProxy::when(const ScriptValuePointer& expression) { +QObject* RouteBuilderProxy::when(const ScriptValue& expression) { // FIXME: Support "!" conditional in simple expression and array expression. // Note that "!" is supported when parsing a JSON file, in UserInputMapper::parseConditional(). auto newConditional = _parent.conditionalFor(expression); diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index 22ca8cd2323..db184df1c8c 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -10,7 +10,6 @@ #define hifi_Controllers_Impl_RouteBuilderProxy_h #include -#include #include "Filter.h" #include "Route.h" @@ -21,7 +20,6 @@ class QJSValue; class QJsonValue; class ScriptValue; -using ScriptValuePointer = QSharedPointer; namespace controller { @@ -117,7 +115,7 @@ class RouteBuilderProxy : public QObject { * Controller.disableMapping(MAPPING_NAME); * }); */ - Q_INVOKABLE void to(const ScriptValuePointer& destination); + Q_INVOKABLE void to(const ScriptValue& destination); /*@jsdoc * Enables or disables writing debug information for a route to the program log. @@ -195,7 +193,7 @@ class RouteBuilderProxy : public QObject { * Controller.disableMapping(MAPPING_NAME); * }); */ - Q_INVOKABLE QObject* when(const ScriptValuePointer& expression); + Q_INVOKABLE QObject* when(const ScriptValue& expression); /*@jsdoc * Filters numeric route values to lie between two values; values outside this range are not passed on through the diff --git a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp index d868ad343ef..bd459ca3ffa 100644 --- a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp +++ b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp @@ -25,5 +25,5 @@ void ScriptConditional::updateValue() { return; } - _lastValue = _callable->call()->toBool(); + _lastValue = _callable.call().toBool(); } diff --git a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h index 0ac4cc4434d..156fdaff44b 100644 --- a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h +++ b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.h @@ -11,24 +11,21 @@ #define hifi_Controllers_ScriptConditional_h #include -#include +#include #include "../Conditional.h" -class ScriptValue; -using ScriptValuePointer = QSharedPointer; - namespace controller { class ScriptConditional : public QObject, public Conditional { Q_OBJECT; public: - ScriptConditional(const ScriptValuePointer& callable) : _callable(callable) {} + ScriptConditional(const ScriptValue& callable) : _callable(callable) {} virtual bool satisfied() override; protected: Q_INVOKABLE void updateValue(); private: - ScriptValuePointer _callable; + ScriptValue _callable; bool _lastValue { false }; }; diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp index 90184afd230..8ed5222160c 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp @@ -17,14 +17,14 @@ using namespace controller; -QString formatException(const ScriptValuePointer& exception) { +QString formatException(const ScriptValue& exception) { QString note { "UncaughtException" }; QString result; - const auto message = exception->toString(); - const auto fileName = exception->property("fileName")->toString(); - const auto lineNumber = exception->property("lineNumber")->toString(); - const auto stacktrace = exception->property("stack")->toString(); + const auto message = exception.toString(); + const auto fileName = exception.property("fileName").toString(); + const auto lineNumber = exception.property("lineNumber").toString(); + const auto stacktrace = exception.property("stack").toString(); const QString SCRIPT_EXCEPTION_FORMAT = "[%0] %1 in %2:%3"; const QString SCRIPT_BACKTRACE_SEP = "\n "; @@ -47,13 +47,13 @@ void ScriptEndpoint::updateValue() { return; } - ScriptValuePointer result = _callable->call(); - if (result->isError()) { + ScriptValue result = _callable.call(); + if (result.isError()) { // print JavaScript exception qCDebug(controllers).noquote() << formatException(result); _lastValueRead = 0.0f; - } else if (result->isNumber()) { - _lastValueRead = (float)_callable->call()->toNumber(); + } else if (result.isNumber()) { + _lastValueRead = (float)_callable.call().toNumber(); } else { Pose::fromScriptValue(result, _lastPoseRead); _returnPose = true; @@ -75,10 +75,10 @@ void ScriptEndpoint::internalApply(float value, int sourceID) { Q_ARG(int, sourceID)); return; } - ScriptEnginePointer engine = _callable->engine(); - ScriptValuePointer result = _callable->call(ScriptValuePointer(), + ScriptEnginePointer engine = _callable.engine(); + ScriptValue result = _callable.call(ScriptValue(), ScriptValueList({ engine->newValue(value), engine->newValue(sourceID) })); - if (result->isError()) { + if (result.isError()) { // print JavaScript exception qCDebug(controllers).noquote() << formatException(result); } @@ -94,8 +94,8 @@ void ScriptEndpoint::updatePose() { QMetaObject::invokeMethod(this, "updatePose", Qt::QueuedConnection); return; } - ScriptValuePointer result = _callable->call(); - if (result->isError()) { + ScriptValue result = _callable.call(); + if (result.isError()) { // print JavaScript exception qCDebug(controllers).noquote() << formatException(result); } @@ -117,10 +117,10 @@ void ScriptEndpoint::internalApply(const Pose& newPose, int sourceID) { Q_ARG(int, sourceID)); return; } - ScriptEnginePointer engine = _callable->engine(); - ScriptValuePointer result = _callable->call(ScriptValuePointer(), + ScriptEnginePointer engine = _callable.engine(); + ScriptValue result = _callable.call(ScriptValue(), ScriptValueList({ Pose::toScriptValue(engine.get(), newPose), engine->newValue(sourceID) })); - if (result->isError()) { + if (result.isError()) { // print JavaScript exception qCDebug(controllers).noquote() << formatException(result); } diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h index ff42812c4b2..327cb40eaaf 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h @@ -10,20 +10,17 @@ #ifndef hifi_Controllers_ScriptEndpoint_h #define hifi_Controllers_ScriptEndpoint_h -#include +#include #include "../Endpoint.h" -class ScriptValue; -using ScriptValuePointer = QSharedPointer; - namespace controller { class ScriptEndpoint : public Endpoint { Q_OBJECT; public: using Endpoint::apply; - ScriptEndpoint(const ScriptValuePointer& callable) + ScriptEndpoint(const ScriptValue& callable) : Endpoint(Input::INVALID_INPUT), _callable(callable) { } @@ -42,7 +39,7 @@ class ScriptEndpoint : public Endpoint { Q_INVOKABLE void updatePose(); Q_INVOKABLE virtual void internalApply(const Pose& newValue, int sourceID); private: - ScriptValuePointer _callable; + ScriptValue _callable; float _lastValueRead { 0.0f }; AxisValue _lastValueWritten { 0.0f, 0, false }; diff --git a/libraries/entities-renderer/src/ModelScriptingInterface.cpp b/libraries/entities-renderer/src/ModelScriptingInterface.cpp index ca9fd45242d..7b87c50619d 100644 --- a/libraries/entities-renderer/src/ModelScriptingInterface.cpp +++ b/libraries/entities-renderer/src/ModelScriptingInterface.cpp @@ -41,7 +41,7 @@ QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { return writeOBJToString(meshes); } -ScriptValuePointer ModelScriptingInterface::appendMeshes(MeshProxyList in) { +ScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { // figure out the size of the resulting mesh size_t totalVertexCount { 0 }; size_t totalColorCount { 0 }; @@ -149,13 +149,13 @@ ScriptValuePointer ModelScriptingInterface::appendMeshes(MeshProxyList in) { return meshToScriptValue(_modelScriptEngine.get(), resultProxy); } -ScriptValuePointer ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { +ScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { if (!meshProxy) { - return ScriptValuePointer(false); + return ScriptValue(); } MeshPointer mesh = meshProxy->getMeshPointer(); if (!mesh) { - return ScriptValuePointer(false); + return ScriptValue(); } const auto inverseTransposeTransform = glm::inverse(glm::transpose(transform)); @@ -167,13 +167,13 @@ ScriptValuePointer ModelScriptingInterface::transformMesh(glm::mat4 transform, M return meshToScriptValue(_modelScriptEngine.get(), resultProxy); } -ScriptValuePointer ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) { +ScriptValue ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) { if (!meshProxy) { - return ScriptValuePointer(false); + return ScriptValue(); } MeshPointer mesh = meshProxy->getMeshPointer(); if (!mesh) { - return ScriptValuePointer(false); + return ScriptValue(); } gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); @@ -181,20 +181,20 @@ ScriptValuePointer ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) return _modelScriptEngine->newValue(numVertices); } -ScriptValuePointer ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int vertexIndex) { +ScriptValue ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int vertexIndex) { if (!meshProxy) { - return ScriptValuePointer(false); + return ScriptValue(); } MeshPointer mesh = meshProxy->getMeshPointer(); if (!mesh) { - return ScriptValuePointer(false); + return ScriptValue(); } const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); if (vertexIndex < 0 || vertexIndex >= numVertices) { - return ScriptValuePointer(false); + return ScriptValue(); } glm::vec3 pos = vertexBufferView.get(vertexIndex); @@ -202,7 +202,7 @@ ScriptValuePointer ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int } -ScriptValuePointer ModelScriptingInterface::newMesh(const QVector& vertices, +ScriptValue ModelScriptingInterface::newMesh(const QVector& vertices, const QVector& normals, const QVector& faces) { graphics::MeshPointer mesh(new graphics::Mesh()); diff --git a/libraries/entities-renderer/src/ModelScriptingInterface.h b/libraries/entities-renderer/src/ModelScriptingInterface.h index 61958fae388..70ac4fae9a4 100644 --- a/libraries/entities-renderer/src/ModelScriptingInterface.h +++ b/libraries/entities-renderer/src/ModelScriptingInterface.h @@ -19,11 +19,10 @@ #include #include +#include class ScriptEngine; -class ScriptValue; using ScriptEnginePointer = QSharedPointer; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The Model API provides the ability to manipulate meshes. You can get the meshes for an entity using @@ -61,7 +60,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshProxy[]} meshes - The meshes to combine. * @returns {MeshProxy} The combined mesh. */ - Q_INVOKABLE ScriptValuePointer appendMeshes(MeshProxyList in); + Q_INVOKABLE ScriptValue appendMeshes(MeshProxyList in); /*@jsdoc * Transforms the vertices in a mesh. @@ -70,7 +69,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshProxy} mesh - The mesh to apply the transform to. * @returns {MeshProxy|boolean} The transformed mesh, if valid. false if an error. */ - Q_INVOKABLE ScriptValuePointer transformMesh(glm::mat4 transform, MeshProxy* meshProxy); + Q_INVOKABLE ScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy); /*@jsdoc * Creates a new mesh. @@ -80,7 +79,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshFace[]} faces - The faces in the mesh. * @returns {MeshProxy} A new mesh. */ - Q_INVOKABLE ScriptValuePointer newMesh(const QVector& vertices, + Q_INVOKABLE ScriptValue newMesh(const QVector& vertices, const QVector& normals, const QVector& faces); @@ -90,7 +89,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshProxy} mesh - The mesh to count the vertices in. * @returns {number|boolean} The number of vertices in the mesh, if valid. false if an error. */ - Q_INVOKABLE ScriptValuePointer getVertexCount(MeshProxy* meshProxy); + Q_INVOKABLE ScriptValue getVertexCount(MeshProxy* meshProxy); /*@jsdoc * Gets the position of a vertex in a mesh. @@ -99,7 +98,7 @@ class ModelScriptingInterface : public QObject { * @param {number} index - The index of the vertex to get. * @returns {Vec3|boolean} The local position of the vertex relative to the mesh, if valid. false if an error. */ - Q_INVOKABLE ScriptValuePointer getVertex(MeshProxy* meshProxy, int vertexIndex); + Q_INVOKABLE ScriptValue getVertex(MeshProxy* meshProxy, int vertexIndex); private: ScriptEnginePointer _modelScriptEngine { nullptr }; diff --git a/libraries/entities/src/AmbientLightPropertyGroup.cpp b/libraries/entities/src/AmbientLightPropertyGroup.cpp index 19585943733..b88e7904b1b 100644 --- a/libraries/entities/src/AmbientLightPropertyGroup.cpp +++ b/libraries/entities/src/AmbientLightPropertyGroup.cpp @@ -19,14 +19,14 @@ const float AmbientLightPropertyGroup::DEFAULT_AMBIENT_LIGHT_INTENSITY = 0.5f; -void AmbientLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, +void AmbientLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_LIGHT_INTENSITY, AmbientLight, ambientLight, AmbientIntensity, ambientIntensity); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_LIGHT_URL, AmbientLight, ambientLight, AmbientURL, ambientURL); } -void AmbientLightPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void AmbientLightPropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientLight, ambientIntensity, float, setAmbientIntensity); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientLight, ambientURL, QString, setAmbientURL); diff --git a/libraries/entities/src/AmbientLightPropertyGroup.h b/libraries/entities/src/AmbientLightPropertyGroup.h index dba6d74cac2..4eb447cb77c 100644 --- a/libraries/entities/src/AmbientLightPropertyGroup.h +++ b/libraries/entities/src/AmbientLightPropertyGroup.h @@ -17,7 +17,6 @@ #include -#include #include "EntityItemPropertiesMacros.h" #include "PropertyGroup.h" @@ -28,7 +27,6 @@ class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * Ambient light is defined by the following properties: @@ -41,10 +39,10 @@ using ScriptValuePointer = QSharedPointer; class AmbientLightPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const AmbientLightPropertyGroup& other); diff --git a/libraries/entities/src/AnimationPropertyGroup.cpp b/libraries/entities/src/AnimationPropertyGroup.cpp index 2546251ddb5..fd19e4e9b83 100644 --- a/libraries/entities/src/AnimationPropertyGroup.cpp +++ b/libraries/entities/src/AnimationPropertyGroup.cpp @@ -65,7 +65,7 @@ bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b * @property {boolean} hold=false - true if the rotations and translations of the last frame played are * maintained when the animation stops playing, false if they aren't. */ -void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps); @@ -78,7 +78,7 @@ void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire } -void AnimationPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void AnimationPropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, url, QString, setURL); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, allowTranslation, bool, setAllowTranslation); diff --git a/libraries/entities/src/AnimationPropertyGroup.h b/libraries/entities/src/AnimationPropertyGroup.h index baa27b96136..4f316568c8a 100644 --- a/libraries/entities/src/AnimationPropertyGroup.h +++ b/libraries/entities/src/AnimationPropertyGroup.h @@ -17,7 +17,6 @@ #include -#include #include "EntityItemPropertiesMacros.h" #include "PropertyGroup.h" @@ -28,17 +27,16 @@ class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; class AnimationPropertyGroup : public PropertyGroup { public: static const float MAXIMUM_POSSIBLE_FRAME; // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const AnimationPropertyGroup& other); diff --git a/libraries/entities/src/BloomPropertyGroup.cpp b/libraries/entities/src/BloomPropertyGroup.cpp index 672b3e9623a..83151499257 100644 --- a/libraries/entities/src/BloomPropertyGroup.cpp +++ b/libraries/entities/src/BloomPropertyGroup.cpp @@ -16,13 +16,13 @@ #include "EntityItemProperties.h" #include "EntityItemPropertiesMacros.h" -void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize); } -void BloomPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void BloomPropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomIntensity, float, setBloomIntensity); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomThreshold, float, setBloomThreshold); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomSize, float, setBloomSize); diff --git a/libraries/entities/src/BloomPropertyGroup.h b/libraries/entities/src/BloomPropertyGroup.h index e702236954e..22e2fb3a9eb 100644 --- a/libraries/entities/src/BloomPropertyGroup.h +++ b/libraries/entities/src/BloomPropertyGroup.h @@ -15,8 +15,6 @@ #include #include -#include - #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" @@ -27,7 +25,6 @@ class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; static const float INITIAL_BLOOM_INTENSITY { 0.25f }; static const float INITIAL_BLOOM_THRESHOLD { 0.7f }; @@ -43,10 +40,10 @@ static const float INITIAL_BLOOM_SIZE { 0.9f }; class BloomPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const BloomPropertyGroup& other); diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 6d2280f0bfb..c9f72bedca8 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -79,10 +79,10 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper auto oldProperties = propertiesIn.getDesiredProperties(); auto specifiedProperties = propertiesIn.getChangedProperties(); propertiesIn.setDesiredProperties(specifiedProperties); - ScriptValuePointer inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true); + ScriptValue inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true); propertiesIn.setDesiredProperties(oldProperties); - auto in = QJsonValue::fromVariant(inputValues->toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. + auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. ScriptValueList args; args << inputValues; @@ -91,7 +91,7 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper // get the current properties for then entity and include them for the filter call if (existingEntity && filterData.wantsOriginalProperties) { auto currentProperties = existingEntity->getProperties(filterData.includedOriginalProperties); - ScriptValuePointer currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); + ScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); args << currentValues; } @@ -101,22 +101,22 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper auto zoneEntity = _tree->findEntityByEntityItemID(id); if (zoneEntity) { auto zoneProperties = zoneEntity->getProperties(filterData.includedZoneProperties); - ScriptValuePointer zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); + ScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); if (filterData.wantsZoneBoundingBox) { bool success = true; AABox aaBox = zoneEntity->getAABox(success); if (success) { - ScriptValuePointer boundingBox = filterData.engine->newObject(); - ScriptValuePointer bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner()); - ScriptValuePointer topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft()); - ScriptValuePointer center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter()); - ScriptValuePointer boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions()); - boundingBox->setProperty("brn", bottomRightNear); - boundingBox->setProperty("tfl", topFarLeft); - boundingBox->setProperty("center", center); - boundingBox->setProperty("dimensions", boundingBoxDimensions); - zoneValues->setProperty("boundingBox", boundingBox); + ScriptValue boundingBox = filterData.engine->newObject(); + ScriptValue bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner()); + ScriptValue topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft()); + ScriptValue center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter()); + ScriptValue boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions()); + boundingBox.setProperty("brn", bottomRightNear); + boundingBox.setProperty("tfl", topFarLeft); + boundingBox.setProperty("center", center); + boundingBox.setProperty("dimensions", boundingBoxDimensions); + zoneValues.setProperty("boundingBox", boundingBox); } } @@ -125,32 +125,32 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper // to be the fourth parameter, so we need to pad the args accordingly int EXPECTED_ARGS = 3; if (args.length() < EXPECTED_ARGS) { - args << ScriptValuePointer(); + args << ScriptValue(); } assert(args.length() == EXPECTED_ARGS); // we MUST have 3 args by now! args << zoneValues; } } - ScriptValuePointer result = filterData.filterFn->call(_nullObjectForFilter, args); + ScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args); if (filterData.uncaughtExceptions()) { return false; } - if (result->isObject()) { + if (result.isObject()) { // make propertiesIn reflect the changes, for next filter... propertiesIn.copyFromScriptValue(result, false); // and update propertiesOut too. TODO: this could be more efficient... propertiesOut.copyFromScriptValue(result, false); // Javascript objects are == only if they are the same object. To compare arbitrary values, we need to use JSON. - auto out = QJsonValue::fromVariant(result->toVariant()); + auto out = QJsonValue::fromVariant(result.toVariant()); wasChanged |= (in != out); - } else if (result->isBool()) { + } else if (result.isBool()) { // if the filter returned false, then it's authoritative - if (!result->toBool()) { + if (!result.toBool()) { return false; } @@ -235,7 +235,7 @@ static bool hasCorrectSyntax(const ScriptProgramPointer& program) { static bool hadUncaughtExceptions(ScriptEngine& engine, const QString& fileName) { if (engine.hasUncaughtException()) { const auto backtrace = engine.uncaughtExceptionBacktrace(); - const auto exception = engine.uncaughtException()->toString(); + const auto exception = engine.uncaughtException().toString(); const auto line = QString::number(engine.uncaughtExceptionLineNumber()); engine.clearExceptions(); @@ -267,7 +267,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { engine->setProperty("type", "edit_filter"); engine->setProperty("fileName", urlString); engine->setProperty("entityID", entityID); - engine->globalObject()->setProperty("Script", engine->newQObject(manager.get())); + engine->globalObject().setProperty("Script", engine->newQObject(manager.get())); DependencyManager::get()->runScriptInitializers(engine.data()); engine->evaluate(scriptContents, urlString); if (!hadUncaughtExceptions(*engine, urlString)) { @@ -283,68 +283,68 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { // now get the filter function auto global = engine->globalObject(); auto entitiesObject = engine->newObject(); - entitiesObject->setProperty("ADD_FILTER_TYPE", EntityTree::FilterType::Add); - entitiesObject->setProperty("EDIT_FILTER_TYPE", EntityTree::FilterType::Edit); - entitiesObject->setProperty("PHYSICS_FILTER_TYPE", EntityTree::FilterType::Physics); - entitiesObject->setProperty("DELETE_FILTER_TYPE", EntityTree::FilterType::Delete); - global->setProperty("Entities", entitiesObject); - filterData.filterFn = global->property("filter"); - if (!filterData.filterFn->isFunction()) { + entitiesObject.setProperty("ADD_FILTER_TYPE", EntityTree::FilterType::Add); + entitiesObject.setProperty("EDIT_FILTER_TYPE", EntityTree::FilterType::Edit); + entitiesObject.setProperty("PHYSICS_FILTER_TYPE", EntityTree::FilterType::Physics); + entitiesObject.setProperty("DELETE_FILTER_TYPE", EntityTree::FilterType::Delete); + global.setProperty("Entities", entitiesObject); + filterData.filterFn = global.property("filter"); + if (!filterData.filterFn.isFunction()) { qDebug() << "Filter function specified but not found. Will reject all edits for those without lock rights."; engine.reset(); filterData.rejectAll=true; } // if the wantsToFilterEdit is a boolean evaluate as a boolean, otherwise assume true - ScriptValuePointer wantsToFilterAddValue = filterData.filterFn->property("wantsToFilterAdd"); - filterData.wantsToFilterAdd = wantsToFilterAddValue->isBool() ? wantsToFilterAddValue->toBool() : true; + ScriptValue wantsToFilterAddValue = filterData.filterFn.property("wantsToFilterAdd"); + filterData.wantsToFilterAdd = wantsToFilterAddValue.isBool() ? wantsToFilterAddValue.toBool() : true; // if the wantsToFilterEdit is a boolean evaluate as a boolean, otherwise assume true - ScriptValuePointer wantsToFilterEditValue = filterData.filterFn->property("wantsToFilterEdit"); - filterData.wantsToFilterEdit = wantsToFilterEditValue->isBool() ? wantsToFilterEditValue->toBool() : true; + ScriptValue wantsToFilterEditValue = filterData.filterFn.property("wantsToFilterEdit"); + filterData.wantsToFilterEdit = wantsToFilterEditValue.isBool() ? wantsToFilterEditValue.toBool() : true; // if the wantsToFilterPhysics is a boolean evaluate as a boolean, otherwise assume true - ScriptValuePointer wantsToFilterPhysicsValue = filterData.filterFn->property("wantsToFilterPhysics"); - filterData.wantsToFilterPhysics = wantsToFilterPhysicsValue->isBool() ? wantsToFilterPhysicsValue->toBool() : true; + ScriptValue wantsToFilterPhysicsValue = filterData.filterFn.property("wantsToFilterPhysics"); + filterData.wantsToFilterPhysics = wantsToFilterPhysicsValue.isBool() ? wantsToFilterPhysicsValue.toBool() : true; // if the wantsToFilterDelete is a boolean evaluate as a boolean, otherwise assume false - ScriptValuePointer wantsToFilterDeleteValue = filterData.filterFn->property("wantsToFilterDelete"); - filterData.wantsToFilterDelete = wantsToFilterDeleteValue->isBool() ? wantsToFilterDeleteValue->toBool() : false; + ScriptValue wantsToFilterDeleteValue = filterData.filterFn.property("wantsToFilterDelete"); + filterData.wantsToFilterDelete = wantsToFilterDeleteValue.isBool() ? wantsToFilterDeleteValue.toBool() : false; // check to see if the filterFn has properties asking for Original props - ScriptValuePointer wantsOriginalPropertiesValue = filterData.filterFn->property("wantsOriginalProperties"); + ScriptValue wantsOriginalPropertiesValue = filterData.filterFn.property("wantsOriginalProperties"); // if the wantsOriginalProperties is a boolean, or a string, or list of strings, then evaluate as follows: // - boolean - true - include all original properties // false - no properties at all // - string - empty - no properties at all // any valid property - include just that property in the Original properties // - list of strings - include only those properties in the Original properties - if (wantsOriginalPropertiesValue->isBool()) { - filterData.wantsOriginalProperties = wantsOriginalPropertiesValue->toBool(); - } else if (wantsOriginalPropertiesValue->isString()) { - auto stringValue = wantsOriginalPropertiesValue->toString(); + if (wantsOriginalPropertiesValue.isBool()) { + filterData.wantsOriginalProperties = wantsOriginalPropertiesValue.toBool(); + } else if (wantsOriginalPropertiesValue.isString()) { + auto stringValue = wantsOriginalPropertiesValue.toString(); filterData.wantsOriginalProperties = !stringValue.isEmpty(); if (filterData.wantsOriginalProperties) { EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); } - } else if (wantsOriginalPropertiesValue->isArray()) { + } else if (wantsOriginalPropertiesValue.isArray()) { EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); filterData.wantsOriginalProperties = !filterData.includedOriginalProperties.isEmpty(); } // check to see if the filterFn has properties asking for Zone props - ScriptValuePointer wantsZonePropertiesValue = filterData.filterFn->property("wantsZoneProperties"); + ScriptValue wantsZonePropertiesValue = filterData.filterFn.property("wantsZoneProperties"); // if the wantsZoneProperties is a boolean, or a string, or list of strings, then evaluate as follows: // - boolean - true - include all Zone properties // false - no properties at all // - string - empty - no properties at all // any valid property - include just that property in the Zone properties // - list of strings - include only those properties in the Zone properties - if (wantsZonePropertiesValue->isBool()) { - filterData.wantsZoneProperties = wantsZonePropertiesValue->toBool(); + if (wantsZonePropertiesValue.isBool()) { + filterData.wantsZoneProperties = wantsZonePropertiesValue.toBool(); filterData.wantsZoneBoundingBox = filterData.wantsZoneProperties; // include this too - } else if (wantsZonePropertiesValue->isString()) { - auto stringValue = wantsZonePropertiesValue->toString(); + } else if (wantsZonePropertiesValue.isString()) { + auto stringValue = wantsZonePropertiesValue.toString(); filterData.wantsZoneProperties = !stringValue.isEmpty(); if (filterData.wantsZoneProperties) { if (stringValue == "boundingBox") { @@ -353,10 +353,10 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { EntityPropertyFlagsFromScriptValue(wantsZonePropertiesValue, filterData.includedZoneProperties); } } - } else if (wantsZonePropertiesValue->isArray()) { - auto length = wantsZonePropertiesValue->property("length")->toInteger(); + } else if (wantsZonePropertiesValue.isArray()) { + auto length = wantsZonePropertiesValue.property("length").toInteger(); for (int i = 0; i < length; i++) { - auto stringValue = wantsZonePropertiesValue->property(i)->toString(); + auto stringValue = wantsZonePropertiesValue.property(i).toString(); if (!stringValue.isEmpty()) { filterData.wantsZoneProperties = true; diff --git a/libraries/entities/src/EntityEditFilters.h b/libraries/entities/src/EntityEditFilters.h index 26dd91cc68b..bf0653a6a41 100644 --- a/libraries/entities/src/EntityEditFilters.h +++ b/libraries/entities/src/EntityEditFilters.h @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -30,7 +29,7 @@ class EntityEditFilters : public QObject, public Dependency { Q_OBJECT public: struct FilterData { - ScriptValuePointer filterFn; + ScriptValue filterFn; bool wantsOriginalProperties { false }; bool wantsZoneProperties { false }; @@ -48,7 +47,7 @@ class EntityEditFilters : public QObject, public Dependency { bool rejectAll; FilterData(): engine(nullptr), rejectAll(false) {}; - bool valid() { return (rejectAll || (engine != nullptr && filterFn->isFunction() && uncaughtExceptions)); } + bool valid() { return (rejectAll || (engine != nullptr && filterFn.isFunction() && uncaughtExceptions)); } }; EntityEditFilters() {}; @@ -71,7 +70,7 @@ private slots: EntityTreePointer _tree {}; bool _rejectAll {false}; - ScriptValuePointer _nullObjectForFilter{}; + ScriptValue _nullObjectForFilter{}; QReadWriteLock _lock; QMap _filterDataMap; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5098cce69fd..061f97cc738 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1572,14 +1572,14 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {Entities.RingGizmo} ring - The ring gizmo properties. */ -ScriptValuePointer EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, +ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, bool strictSemantics, EntityPsuedoPropertyFlags psueudoPropertyFlags) const { // If strictSemantics is true and skipDefaults is false, then all and only those properties are copied for which the property flag // is included in _desiredProperties, or is one of the specially enumerated ALWAYS properties below. // (There may be exceptions, but if so, they are bugs.) // In all other cases, you are welcome to inspect the code and try to figure out what was intended. I wish you luck. -HRS 1/18/17 - ScriptValuePointer properties = engine->newObject(); + ScriptValue properties = engine->newObject(); EntityItemProperties defaultEntityProperties; const bool psuedoPropertyFlagsActive = psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::FlagsActive); @@ -1606,7 +1606,7 @@ ScriptValuePointer EntityItemProperties::copyToScriptValue(ScriptEngine* engine, } } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::LastEdited)) { - properties->setProperty("lastEdited", convertScriptValue(engine, _lastEdited)); + properties.setProperty("lastEdited", convertScriptValue(engine, _lastEdited)); } if (!skipDefaults) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, naturalDimensions); // gettable, but not settable @@ -1923,9 +1923,9 @@ ScriptValuePointer EntityItemProperties::copyToScriptValue(ScriptEngine* engine, // Handle conversions to old 'textures' property from "imageURL" if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(PROP_IMAGE_URL)) && (!skipDefaults || defaultEntityProperties._imageURL != _imageURL)) { - ScriptValuePointer textures = engine->newObject(); - textures->setProperty("tex.picture", _imageURL); - properties->setProperty("textures", textures); + ScriptValue textures = engine->newObject(); + textures.setProperty("tex.picture", _imageURL); + properties.setProperty("textures", textures); } } @@ -1958,15 +1958,15 @@ ScriptValuePointer EntityItemProperties::copyToScriptValue(ScriptEngine* engine, (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::BoundingBox))) { AABox aaBox = getAABox(); - ScriptValuePointer boundingBox = engine->newObject(); - ScriptValuePointer bottomRightNear = vec3ToScriptValue(engine, aaBox.getCorner()); - ScriptValuePointer topFarLeft = vec3ToScriptValue(engine, aaBox.calcTopFarLeft()); - ScriptValuePointer center = vec3ToScriptValue(engine, aaBox.calcCenter()); - ScriptValuePointer boundingBoxDimensions = vec3ToScriptValue(engine, aaBox.getDimensions()); - boundingBox->setProperty("brn", bottomRightNear); - boundingBox->setProperty("tfl", topFarLeft); - boundingBox->setProperty("center", center); - boundingBox->setProperty("dimensions", boundingBoxDimensions); + ScriptValue boundingBox = engine->newObject(); + ScriptValue bottomRightNear = vec3ToScriptValue(engine, aaBox.getCorner()); + ScriptValue topFarLeft = vec3ToScriptValue(engine, aaBox.calcTopFarLeft()); + ScriptValue center = vec3ToScriptValue(engine, aaBox.calcCenter()); + ScriptValue boundingBoxDimensions = vec3ToScriptValue(engine, aaBox.getDimensions()); + boundingBox.setProperty("brn", bottomRightNear); + boundingBox.setProperty("tfl", topFarLeft); + boundingBox.setProperty("center", center); + boundingBox.setProperty("dimensions", boundingBoxDimensions); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable } @@ -1979,7 +1979,7 @@ ScriptValuePointer EntityItemProperties::copyToScriptValue(ScriptEngine* engine, if (!skipDefaults && !strictSemantics && (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::RenderInfo))) { - ScriptValuePointer renderInfo = engine->newObject(); + ScriptValue renderInfo = engine->newObject(); /*@jsdoc * Information on how an entity is rendered. Properties are only filled in for Model entities; other @@ -1994,40 +1994,40 @@ ScriptValuePointer EntityItemProperties::copyToScriptValue(ScriptEngine* engine, */ // currently only supported by models if (_type == EntityTypes::Model) { - renderInfo->setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int - renderInfo->setProperty("texturesSize", (int)getRenderInfoTextureSize()); // FIXME - theoretically the size of textures could be > max int - renderInfo->setProperty("hasTransparent", getRenderInfoHasTransparent()); - renderInfo->setProperty("drawCalls", getRenderInfoDrawCalls()); - renderInfo->setProperty("texturesCount", getRenderInfoTextureCount()); + renderInfo.setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int + renderInfo.setProperty("texturesSize", (int)getRenderInfoTextureSize()); // FIXME - theoretically the size of textures could be > max int + renderInfo.setProperty("hasTransparent", getRenderInfoHasTransparent()); + renderInfo.setProperty("drawCalls", getRenderInfoDrawCalls()); + renderInfo.setProperty("texturesCount", getRenderInfoTextureCount()); } COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::ClientOnly)) { - properties->setProperty("clientOnly", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); + properties.setProperty("clientOnly", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::AvatarEntity)) { - properties->setProperty("avatarEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); + properties.setProperty("avatarEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::LocalEntity)) { - properties->setProperty("localEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::LOCAL)); + properties.setProperty("localEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::LOCAL)); } if (_type != EntityTypes::PolyLine && (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::FaceCamera))) { - properties->setProperty("faceCamera", convertScriptValue(engine, getBillboardMode() == BillboardMode::YAW)); + properties.setProperty("faceCamera", convertScriptValue(engine, getBillboardMode() == BillboardMode::YAW)); } if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::IsFacingAvatar)) { - properties->setProperty("isFacingAvatar", convertScriptValue(engine, getBillboardMode() == BillboardMode::FULL)); + properties.setProperty("isFacingAvatar", convertScriptValue(engine, getBillboardMode() == BillboardMode::FULL)); } return properties; } -void EntityItemProperties::copyFromScriptValue(const ScriptValuePointer& object, bool honorReadOnly) { - ScriptValuePointer typeScriptValue = object->property("type"); - if (typeScriptValue->isValid()) { - setType(typeScriptValue->toVariant().toString()); +void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool honorReadOnly) { + ScriptValue typeScriptValue = object.property("type"); + if (typeScriptValue.isValid()) { + setType(typeScriptValue.toVariant().toString()); } // Core @@ -2280,8 +2280,8 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValuePointer& object, // Handle conversions from old 'textures' property to "imageURL" { - ScriptValuePointer V = object->property("textures"); - if (_type == EntityTypes::Image && V->isValid() && !object->property("imageURL")->isValid()) { + ScriptValue V = object.property("textures"); + if (_type == EntityTypes::Image && V.isValid() && !object.property("imageURL").isValid()) { bool isValid = false; QString textures = QString_convertFromScriptValue(V, isValid); if (isValid) { @@ -2299,9 +2299,9 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValuePointer& object, // Handle old "faceCamera" and "isFacingAvatar" props if (_type != EntityTypes::PolyLine) { - ScriptValuePointer P = object->property("faceCamera"); - if (P->isValid() && !object->property("billboardMode")->isValid()) { - bool newValue = P->toVariant().toBool(); + ScriptValue P = object.property("faceCamera"); + if (P.isValid() && !object.property("billboardMode").isValid()) { + bool newValue = P.toVariant().toBool(); bool oldValue = getBillboardMode() == BillboardMode::YAW; if (_defaultSettings || newValue != oldValue) { setBillboardMode(newValue ? BillboardMode::YAW : BillboardMode::NONE); @@ -2309,9 +2309,9 @@ void EntityItemProperties::copyFromScriptValue(const ScriptValuePointer& object, } } { - ScriptValuePointer P = object->property("isFacingAvatar"); - if (P->isValid() && !object->property("billboardMode")->isValid() && !object->property("faceCamera")->isValid()) { - bool newValue = P->toVariant().toBool(); + ScriptValue P = object.property("isFacingAvatar"); + if (P.isValid() && !object.property("billboardMode").isValid() && !object.property("faceCamera").isValid()) { + bool newValue = P.toVariant().toBool(); bool oldValue = getBillboardMode() == BillboardMode::FULL; if (_defaultSettings || newValue != oldValue) { setBillboardMode(newValue ? BillboardMode::FULL : BillboardMode::NONE); @@ -2328,7 +2328,7 @@ void EntityItemProperties::copyFromJSONString(ScriptEngine& scriptEngine, const QJsonObject propertiesObj = propertiesDoc.object(); QVariant propertiesVariant(propertiesObj); QVariantMap propertiesMap = propertiesVariant.toMap(); - ScriptValuePointer propertiesScriptValue = variantMapToScriptValue(propertiesMap, scriptEngine); + ScriptValue propertiesScriptValue = variantMapToScriptValue(propertiesMap, scriptEngine); bool honorReadOnly = true; copyFromScriptValue(propertiesScriptValue, honorReadOnly); } @@ -2576,47 +2576,47 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { _lastEdited = usecTimestampNow(); } -ScriptValuePointer EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { +ScriptValue EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { return properties.copyToScriptValue(engine, false); } -ScriptValuePointer EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { +ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { return properties.copyToScriptValue(engine, true); } -void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValuePointer &object, EntityItemProperties& properties) { +void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue &object, EntityItemProperties& properties) { properties.copyFromScriptValue(object, false); } -void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValuePointer &object, EntityItemProperties& properties) { +void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue &object, EntityItemProperties& properties) { properties.copyFromScriptValue(object, true); } -ScriptValuePointer EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { +ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { return EntityItemProperties::entityPropertyFlagsToScriptValue(engine, flags); } -void EntityPropertyFlagsFromScriptValue(const ScriptValuePointer& object, EntityPropertyFlags& flags) { +void EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags); } -ScriptValuePointer EntityItemProperties::entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { - ScriptValuePointer result = engine->newObject(); +ScriptValue EntityItemProperties::entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { + ScriptValue result = engine->newObject(); return result; } -void EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValuePointer& object, EntityPropertyFlags& flags) { - if (object->isString()) { +void EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { + if (object.isString()) { EntityPropertyInfo propertyInfo; - if (getPropertyInfo(object->toString(), propertyInfo)) { + if (getPropertyInfo(object.toString(), propertyInfo)) { flags << propertyInfo.propertyEnum; } } - else if (object->isArray()) { - quint32 length = object->property("length")->toInt32(); + else if (object.isArray()) { + quint32 length = object.property("length").toInt32(); for (quint32 i = 0; i < length; i++) { - QString propertyName = object->property(i)->toString(); + QString propertyName = object.property(i).toString(); EntityPropertyInfo propertyInfo; if (getPropertyInfo(propertyName, propertyInfo)) { flags << propertyInfo.propertyEnum; @@ -3015,18 +3015,18 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr * @property {string} minimum - The minimum numerical value the property may have, if available, otherwise "". * @property {string} maximum - The maximum numerical value the property may have, if available, otherwise "". */ -ScriptValuePointer EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("propertyEnum", propertyInfo.propertyEnum); - obj->setProperty("minimum", propertyInfo.minimum.toString()); - obj->setProperty("maximum", propertyInfo.maximum.toString()); +ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo) { + ScriptValue obj = engine->newObject(); + obj.setProperty("propertyEnum", propertyInfo.propertyEnum); + obj.setProperty("minimum", propertyInfo.minimum.toString()); + obj.setProperty("maximum", propertyInfo.maximum.toString()); return obj; } -void EntityPropertyInfoFromScriptValue(const ScriptValuePointer& object, EntityPropertyInfo& propertyInfo) { - propertyInfo.propertyEnum = (EntityPropertyList)object->property("propertyEnum")->toVariant().toUInt(); - propertyInfo.minimum = object->property("minimum")->toVariant(); - propertyInfo.maximum = object->property("maximum")->toVariant(); +void EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo) { + propertyInfo.propertyEnum = (EntityPropertyList)object.property("propertyEnum").toVariant().toUInt(); + propertyInfo.minimum = object.property("minimum").toVariant(); + propertyInfo.maximum = object.property("maximum").toVariant(); } // TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the @@ -5210,7 +5210,7 @@ bool EntityItemProperties::blobToProperties(ScriptEngine& scriptEngine, const QB } QVariant variant = jsonProperties.toVariant(); QVariantMap variantMap = variant.toMap(); - ScriptValuePointer scriptValue = variantMapToScriptValue(variantMap, scriptEngine); + ScriptValue scriptValue = variantMapToScriptValue(variantMap, scriptEngine); EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptValue, properties); // end recipe return true; @@ -5220,10 +5220,10 @@ void EntityItemProperties::propertiesToBlob(ScriptEngine& scriptEngine, const QU const EntityItemProperties& properties, QByteArray& blob, bool allProperties) { // DANGER: this method is NOT efficient. // begin recipe for extracting unfortunately-formatted-binary-blob from EntityItem - ScriptValuePointer scriptValue = allProperties + ScriptValue scriptValue = allProperties ? EntityItemPropertiesToScriptValue(&scriptEngine, properties) : EntityItemNonDefaultPropertiesToScriptValue(&scriptEngine, properties); - QVariant variantProperties = scriptValue->toVariant(); + QVariant variantProperties = scriptValue.toVariant(); QJsonDocument jsonProperties = QJsonDocument::fromVariant(variantProperties); // the ID of the parent/avatar changes from session to session. use a special UUID to indicate the avatar QJsonObject jsonObject = jsonProperties.object(); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 4184880ad12..c8016461d73 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -34,8 +33,9 @@ #include #include #include "FontFamilies.h" +#include -#include "EntityItemID.h" +#include #include "EntityItemPropertiesDefaults.h" #include "EntityItemPropertiesMacros.h" #include "EntityTypes.h" @@ -70,8 +70,6 @@ #include "TextAlignment.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; const quint64 UNKNOWN_CREATED_TIME = 0; @@ -100,7 +98,7 @@ EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_i } /// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an -/// entity and a JavaScript style hash/ScriptValuePointer storing a set of properties. Used in scripting to set/get the complete +/// entity and a JavaScript style hash/ScriptValue storing a set of properties. Used in scripting to set/get the complete /// set of entity item properties via JavaScript hashes/QScriptValues /// all units for SI units (meter, second, radian, etc) class EntityItemProperties { @@ -137,13 +135,13 @@ class EntityItemProperties { EntityTypes::EntityType getType() const { return _type; } void setType(EntityTypes::EntityType type) { _type = type; } - virtual ScriptValuePointer copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime = false, + virtual ScriptValue copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime = false, bool strictSemantics = false, EntityPsuedoPropertyFlags psueudoPropertyFlags = EntityPsuedoPropertyFlags()) const; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool honorReadOnly); + virtual void copyFromScriptValue(const ScriptValue& object, bool honorReadOnly); void copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString); - static ScriptValuePointer entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); - static void entityPropertyFlagsFromScriptValue(const ScriptValuePointer& object, EntityPropertyFlags& flags); + static ScriptValue entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); + static void entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); static bool getPropertyInfo(const QString& propertyName, EntityPropertyInfo& propertyInfo); @@ -543,18 +541,18 @@ class EntityItemProperties { }; Q_DECLARE_METATYPE(EntityItemProperties); -ScriptValuePointer EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); -ScriptValuePointer EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValuePointer& object, EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValuePointer& object, EntityItemProperties& properties); +ScriptValue EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); +ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); +void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue& object, EntityItemProperties& properties); +void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue& object, EntityItemProperties& properties); Q_DECLARE_METATYPE(EntityPropertyFlags); -ScriptValuePointer EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); -void EntityPropertyFlagsFromScriptValue(const ScriptValuePointer& object, EntityPropertyFlags& flags); +ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); +void EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); Q_DECLARE_METATYPE(EntityPropertyInfo); -ScriptValuePointer EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo); -void EntityPropertyInfoFromScriptValue(const ScriptValuePointer& object, EntityPropertyInfo& propertyInfo); +ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo); +void EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo); // define these inline here so the macros work inline void EntityItemProperties::setPosition(const glm::vec3& value) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 550e822ff2d..7f08d5b03c9 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -13,11 +13,11 @@ #ifndef hifi_EntityItemPropertiesMacros_h #define hifi_EntityItemPropertiesMacros_h -#include "EntityItemID.h" +#include #include -#include "ScriptEngine.h" -#include "ScriptValue.h" -#include "ScriptValueUtils.h" +#include +#include +#include #define APPEND_ENTITY_PROPERTY(P,V) \ if (requestedProperties.getHasProperty(P)) { \ @@ -102,118 +102,118 @@ changedProperties += P; \ } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const glm::vec2& v) { return vec2ToScriptValue(e, v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ToScriptValue(e, v); } -inline ScriptValuePointer vec3Color_convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ColorToScriptValue(e, v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ToScriptValue(e, v); } -inline ScriptValuePointer u8vec3Color_convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ColorToScriptValue(e, v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, float v) { return e->newValue(v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, int v) { return e->newValue(v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, bool v) { return e->newValue(v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, quint16 v) { return e->newValue(v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, quint32 v) { return e->newValue(v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, quint64 v) { return e->newValue((double)v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QString& v) { return e->newValue(v); } - -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const ScriptValuePointer& v) { return v; } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorVec3ToScriptValue(e, v); } -inline ScriptValuePointer qVectorVec3Color_convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorVec3ColorToScriptValue(e, v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorQuatToScriptValue(e, v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorBoolToScriptValue(e, v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorQUuidToScriptValue(e, v); } - -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); } - -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const QByteArray& v) { +inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::vec2& v) { return vec2ToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ToScriptValue(e, v); } +inline ScriptValue vec3Color_convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ColorToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ToScriptValue(e, v); } +inline ScriptValue u8vec3Color_convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ColorToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, float v) { return e->newValue(v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, int v) { return e->newValue(v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, bool v) { return e->newValue(v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, quint16 v) { return e->newValue(v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, quint32 v) { return e->newValue(v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, quint64 v) { return e->newValue((double)v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const QString& v) { return e->newValue(v); } + +inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const ScriptValue& v) { return v; } +inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorVec3ToScriptValue(e, v); } +inline ScriptValue qVectorVec3Color_convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorVec3ColorToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorQuatToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorBoolToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorQUuidToScriptValue(e, v); } + +inline ScriptValue convertScriptValue(ScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); } + +inline ScriptValue convertScriptValue(ScriptEngine* e, const QByteArray& v) { QByteArray b64 = v.toBase64(); return e->newValue(QString(b64)); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const EntityItemID& v) { return e->newValue(QUuid(v).toString()); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const EntityItemID& v) { return e->newValue(QUuid(v).toString()); } -inline ScriptValuePointer convertScriptValue(ScriptEngine* e, const AACube& v) { return aaCubeToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const AACube& v) { return aaCubeToScriptValue(e, v); } #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(X,G,g,P,p) \ if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \ (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \ - ScriptValuePointer groupProperties = properties->property(#g); \ - if (!groupProperties->isValid()) { \ + ScriptValue groupProperties = properties.property(#g); \ + if (!groupProperties.isValid()) { \ groupProperties = engine->newObject(); \ } \ - ScriptValuePointer V = convertScriptValue(engine, get##P()); \ - groupProperties->setProperty(#p, V); \ - properties->setProperty(#g, groupProperties); \ + ScriptValue V = convertScriptValue(engine, get##P()); \ + groupProperties.setProperty(#p, V); \ + properties.setProperty(#g, groupProperties); \ } #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(X,G,g,P,p,T) \ if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \ (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \ - ScriptValuePointer groupProperties = properties->property(#g); \ - if (!groupProperties->isValid()) { \ + ScriptValue groupProperties = properties.property(#g); \ + if (!groupProperties.isValid()) { \ groupProperties = engine->newObject(); \ } \ - ScriptValuePointer V = T##_convertScriptValue(engine, get##P()); \ - groupProperties->setProperty(#p, V); \ - properties->setProperty(#g, groupProperties); \ + ScriptValue V = T##_convertScriptValue(engine, get##P()); \ + groupProperties.setProperty(#p, V); \ + properties.setProperty(#g, groupProperties); \ } #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(X,G,g,P,p,M) \ if ((desiredProperties.isEmpty() || desiredProperties.getHasProperty(X)) && \ (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \ - ScriptValuePointer groupProperties = properties->property(#g); \ - if (!groupProperties->isValid()) { \ + ScriptValue groupProperties = properties.property(#g); \ + if (!groupProperties.isValid()) { \ groupProperties = engine->newObject(); \ } \ - ScriptValuePointer V = convertScriptValue(engine, M()); \ - groupProperties->setProperty(#p, V); \ - properties->setProperty(#g, groupProperties); \ + ScriptValue V = convertScriptValue(engine, M()); \ + groupProperties.setProperty(#p, V); \ + properties.setProperty(#g, groupProperties); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE(p,P) \ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - ScriptValuePointer V = convertScriptValue(engine, _##P); \ - properties->setProperty(#P, V); \ + ScriptValue V = convertScriptValue(engine, _##P); \ + properties.setProperty(#P, V); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(p,P,T) \ if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - ScriptValuePointer V = T##_convertScriptValue(engine, _##P); \ - properties->setProperty(#P, V); \ + ScriptValue V = T##_convertScriptValue(engine, _##P); \ + properties.setProperty(#P, V); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(P, G) \ - properties->setProperty(#P, G); + properties.setProperty(#P, G); #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, G) \ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - ScriptValuePointer V = convertScriptValue(engine, G); \ - properties->setProperty(#P, V); \ + ScriptValue V = convertScriptValue(engine, G); \ + properties.setProperty(#P, V); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(p, P, G, T) \ if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - ScriptValuePointer V = T##_convertScriptValue(engine, G); \ - properties->setProperty(#P, V); \ + ScriptValue V = T##_convertScriptValue(engine, G); \ + properties.setProperty(#P, V); \ } // same as COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER but uses #X instead of #P in the setProperty() step #define COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, X, G) \ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - ScriptValuePointer V = convertScriptValue(engine, G); \ - properties->setProperty(#X, V); \ + ScriptValue V = convertScriptValue(engine, G); \ + properties.setProperty(#X, V); \ } #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(P, G) \ if (!skipDefaults || defaultEntityProperties._##P != _##P) { \ - ScriptValuePointer V = convertScriptValue(engine, G); \ - properties->setProperty(#P, V); \ + ScriptValue V = convertScriptValue(engine, G); \ + properties.setProperty(#P, V); \ } typedef QVector qVectorVec3; @@ -221,100 +221,100 @@ typedef QVector qVectorQuat; typedef QVector qVectorBool; typedef QVector qVectorFloat; typedef QVector qVectorQUuid; -inline float float_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toFloat(&isValid); } -inline quint64 quint64_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toULongLong(&isValid); } -inline quint32 quint32_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline float float_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); } +inline quint64 quint64_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); } +inline quint32 quint32_convertFromScriptValue(const ScriptValue& v, bool& isValid) { // Use QString::toUInt() so that isValid is set to false if the number is outside the quint32 range. - return v->toString().toUInt(&isValid); + return v.toString().toUInt(&isValid); } -inline quint16 quint16_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toInt(&isValid); } -inline uint16_t uint16_t_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toInt(&isValid); } -inline uint32_t uint32_t_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toInt(&isValid); } -inline int int_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { return v->toVariant().toInt(&isValid); } -inline bool bool_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return v->toVariant().toBool(); } -inline uint8_t uint8_t_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v->toVariant().toInt(&isValid)); } -inline QString QString_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return v->toVariant().toString().trimmed(); } -inline QUuid QUuid_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return v->toVariant().toUuid(); } -inline EntityItemID EntityItemID_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { isValid = true; return v->toVariant().toUuid(); } - -inline QByteArray QByteArray_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline quint16 quint16_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } +inline uint16_t uint16_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } +inline uint32_t uint32_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } +inline int int_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } +inline bool bool_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); } +inline uint8_t uint8_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v.toVariant().toInt(&isValid)); } +inline QString QString_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); } +inline QUuid QUuid_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } +inline EntityItemID EntityItemID_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } + +inline QByteArray QByteArray_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; - QString b64 = v->toVariant().toString().trimmed(); + QString b64 = v.toVariant().toString().trimmed(); return QByteArray::fromBase64(b64.toUtf8()); } -inline glm::vec2 vec2_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline glm::vec2 vec2_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; glm::vec2 vec2; vec2FromScriptValue(v, vec2); return vec2; } -inline glm::vec3 vec3_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline glm::vec3 vec3_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; glm::vec3 vec3; vec3FromScriptValue(v, vec3); return vec3; } -inline glm::vec3 vec3Color_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline glm::vec3 vec3Color_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; glm::vec3 vec3; vec3FromScriptValue(v, vec3); return vec3; } -inline glm::u8vec3 u8vec3Color_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline glm::u8vec3 u8vec3Color_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; glm::u8vec3 vec3; u8vec3FromScriptValue(v, vec3); return vec3; } -inline AACube AACube_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline AACube AACube_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; AACube result; aaCubeFromScriptValue(v, result); return result; } -inline qVectorFloat qVectorFloat_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline qVectorFloat qVectorFloat_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return qVectorFloatFromScriptValue(v); } -inline qVectorVec3 qVectorVec3_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline qVectorVec3 qVectorVec3_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return qVectorVec3FromScriptValue(v); } -inline qVectorQuat qVectorQuat_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline qVectorQuat qVectorQuat_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return qVectorQuatFromScriptValue(v); } -inline qVectorBool qVectorBool_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline qVectorBool qVectorBool_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return qVectorBoolFromScriptValue(v); } -inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return qVectorQUuidFromScriptValue(v); } -inline glm::quat quat_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline glm::quat quat_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = false; /// assume it can't be converted - ScriptValuePointer x = v->property("x"); - ScriptValuePointer y = v->property("y"); - ScriptValuePointer z = v->property("z"); - ScriptValuePointer w = v->property("w"); - if (x->isValid() && y->isValid() && z->isValid() && w->isValid()) { + ScriptValue x = v.property("x"); + ScriptValue y = v.property("y"); + ScriptValue z = v.property("z"); + ScriptValue w = v.property("w"); + if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { glm::quat newValue; - newValue.x = x->toVariant().toFloat(); - newValue.y = y->toVariant().toFloat(); - newValue.z = z->toVariant().toFloat(); - newValue.w = w->toVariant().toFloat(); + newValue.x = x.toVariant().toFloat(); + newValue.y = y.toVariant().toFloat(); + newValue.z = z.toVariant().toFloat(); + newValue.w = w.toVariant().toFloat(); isValid = !glm::isnan(newValue.x) && !glm::isnan(newValue.y) && !glm::isnan(newValue.z) && @@ -326,7 +326,7 @@ inline glm::quat quat_convertFromScriptValue(const ScriptValuePointer& v, bool& return glm::quat(); } -inline QRect QRect_convertFromScriptValue(const ScriptValuePointer& v, bool& isValid) { +inline QRect QRect_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; QRect rect; qRectFromScriptValue(v, rect); @@ -344,8 +344,8 @@ inline QRect QRect_convertFromScriptValue(const ScriptValuePointer& v, bool& isV #define COPY_PROPERTY_FROM_QSCRIPTVALUE(P, T, S) \ { \ - ScriptValuePointer V = object->property(#P); \ - if (V->isValid()) { \ + ScriptValue V = object.property(#P); \ + if (V.isValid()) { \ bool isValid = false; \ T newValue = T##_convertFromScriptValue(V, isValid); \ if (isValid && (_defaultSettings || newValue != _##P)) { \ @@ -356,8 +356,8 @@ inline QRect QRect_convertFromScriptValue(const ScriptValuePointer& v, bool& isV #define COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(P, T, S, G) \ { \ - ScriptValuePointer V = object->property(#P); \ - if (V->isValid()) { \ + ScriptValue V = object.property(#P); \ + if (V.isValid()) { \ bool isValid = false; \ T newValue = T##_convertFromScriptValue(V, isValid); \ if (isValid && (_defaultSettings || newValue != G())) { \ @@ -368,8 +368,8 @@ inline QRect QRect_convertFromScriptValue(const ScriptValuePointer& v, bool& isV #define COPY_PROPERTY_FROM_QSCRIPTVALUE_NOCHECK(P, T, S) \ { \ - ScriptValuePointer V = object->property(#P); \ - if (V->isValid()) { \ + ScriptValue V = object.property(#P); \ + if (V.isValid()) { \ bool isValid = false; \ T newValue = T##_convertFromScriptValue(V, isValid); \ if (isValid && (_defaultSettings)) { \ @@ -380,10 +380,10 @@ inline QRect QRect_convertFromScriptValue(const ScriptValuePointer& v, bool& isV #define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(G, P, T, S) \ { \ - ScriptValuePointer G = object->property(#G); \ - if (G->isValid()) { \ - ScriptValuePointer V = G->property(#P); \ - if (V->isValid()) { \ + ScriptValue G = object.property(#G); \ + if (G.isValid()) { \ + ScriptValue V = G.property(#P); \ + if (V.isValid()) { \ bool isValid = false; \ T newValue = T##_convertFromScriptValue(V, isValid); \ if (isValid && (_defaultSettings || newValue != _##P)) { \ @@ -395,9 +395,9 @@ inline QRect QRect_convertFromScriptValue(const ScriptValuePointer& v, bool& isV #define COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(P, S) \ { \ - ScriptValuePointer P = object->property(#P); \ - if (P->isValid()) { \ - QString newValue = P->toVariant().toString(); \ + ScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + QString newValue = P.toVariant().toString(); \ if (_defaultSettings || newValue != get##S##AsString()) { \ set##S##FromString(newValue); \ } \ @@ -406,11 +406,11 @@ inline QRect QRect_convertFromScriptValue(const ScriptValuePointer& v, bool& isV #define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(G, P, S) \ { \ - ScriptValuePointer G = object->property(#G); \ - if (G->isValid()) { \ - ScriptValuePointer P = G->property(#P); \ - if (P->isValid()) { \ - QString newValue = P->toVariant().toString(); \ + ScriptValue G = object.property(#G); \ + if (G.isValid()) { \ + ScriptValue P = G.property(#P); \ + if (P.isValid()) { \ + QString newValue = P.toVariant().toString(); \ if (_defaultSettings || newValue != get##S##AsString()) { \ set##S##FromString(newValue); \ } \ diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f3723b17444..e9098c822b5 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -846,7 +846,7 @@ struct EntityPropertiesResult { // Static method to make sure that we have the right script engine. // Using sender() or QtScriptable::engine() does not work for classes used by multiple threads (script-engines) -ScriptValuePointer EntityScriptingInterface::getMultipleEntityProperties(ScriptContext* context, ScriptEngine* engine) { +ScriptValue EntityScriptingInterface::getMultipleEntityProperties(ScriptContext* context, ScriptEngine* engine) { const int ARGUMENT_ENTITY_IDS = 0; const int ARGUMENT_EXTENDED_DESIRED_PROPERTIES = 1; @@ -855,12 +855,12 @@ ScriptValuePointer EntityScriptingInterface::getMultipleEntityProperties(ScriptC return entityScriptingInterface->getMultipleEntityPropertiesInternal(engine, entityIDs, context->argument(ARGUMENT_EXTENDED_DESIRED_PROPERTIES)); } -ScriptValuePointer EntityScriptingInterface::getMultipleEntityPropertiesInternal(ScriptEngine* engine, QVector entityIDs, const ScriptValuePointer& extendedDesiredProperties) { +ScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(ScriptEngine* engine, QVector entityIDs, const ScriptValue& extendedDesiredProperties) { PROFILE_RANGE(script_entities, __FUNCTION__); EntityPsuedoPropertyFlags psuedoPropertyFlags; - const auto readExtendedPropertyStringValue = [&](ScriptValuePointer extendedProperty) { - const auto extendedPropertyString = extendedProperty->toString(); + const auto readExtendedPropertyStringValue = [&](ScriptValue extendedProperty) { + const auto extendedPropertyString = extendedProperty.toString(); if (extendedPropertyString == "id") { psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::ID); } else if (extendedPropertyString == "type") { @@ -890,13 +890,13 @@ ScriptValuePointer EntityScriptingInterface::getMultipleEntityPropertiesInternal } }; - if (extendedDesiredProperties->isString()) { + if (extendedDesiredProperties.isString()) { readExtendedPropertyStringValue(extendedDesiredProperties); psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FlagsActive); - } else if (extendedDesiredProperties->isArray()) { - const quint32 length = extendedDesiredProperties->property("length")->toInt32(); + } else if (extendedDesiredProperties.isArray()) { + const quint32 length = extendedDesiredProperties.property("length").toInt32(); for (quint32 i = 0; i < length; i++) { - readExtendedPropertyStringValue(extendedDesiredProperties->property(i)); + readExtendedPropertyStringValue(extendedDesiredProperties.property(i)); } psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FlagsActive); } @@ -948,18 +948,18 @@ ScriptValuePointer EntityScriptingInterface::getMultipleEntityPropertiesInternal }); } } - ScriptValuePointer finalResult = engine->newArray(resultProperties.size()); + ScriptValue finalResult = engine->newArray(resultProperties.size()); quint32 i = 0; if (needsScriptSemantics) { PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Script Semantics"); foreach(const auto& result, resultProperties) { - finalResult->setProperty(i++, convertPropertiesToScriptSemantics(result.properties, result.scalesWithParent) + finalResult.setProperty(i++, convertPropertiesToScriptSemantics(result.properties, result.scalesWithParent) .copyToScriptValue(engine, false, false, false, psuedoPropertyFlags)); } } else { PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Skip Script Semantics"); foreach(const auto& result, resultProperties) { - finalResult->setProperty(i++, result.properties.copyToScriptValue(engine, false, false, false, psuedoPropertyFlags)); + finalResult.setProperty(i++, result.properties.copyToScriptValue(engine, false, false, false, psuedoPropertyFlags)); } } return finalResult; @@ -1432,7 +1432,7 @@ QVector EntityScriptingInterface::findEntitiesByName(const QString entity } RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, - const ScriptValuePointer& entityIdsToInclude, const ScriptValuePointer& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) const { + const ScriptValue& entityIdsToInclude, const ScriptValue& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) const { PROFILE_RANGE(script_entities, __FUNCTION__); QVector entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); @@ -1508,13 +1508,13 @@ bool EntityScriptingInterface::reloadServerScripts(const QUuid& entityID) { return client->reloadServerScript(entityID); } -bool EntityPropertyMetadataRequest::script(EntityItemID entityID, ScriptValuePointer handler) { +bool EntityPropertyMetadataRequest::script(EntityItemID entityID, const ScriptValue& handler) { using LocalScriptStatusRequest = QFutureWatcher; LocalScriptStatusRequest* request = new LocalScriptStatusRequest; QObject::connect(request, &LocalScriptStatusRequest::finished, _manager, [=]() mutable { auto details = request->result().toMap(); - ScriptValuePointer err, result; + ScriptValue err, result; if (details.contains("isError")) { if (!details.contains("message")) { details["message"] = details["errorInfo"]; @@ -1535,14 +1535,14 @@ bool EntityPropertyMetadataRequest::script(EntityItemID entityID, ScriptValuePoi }, entityID); if (!request->isStarted()) { request->deleteLater(); - auto engine = handler->engine(); - callScopedHandlerObject(handler, engine->makeError(engine->newValue("Entities Scripting Provider unavailable"), "InternalError"), ScriptValuePointer()); + auto engine = handler.engine(); + callScopedHandlerObject(handler, engine->makeError(engine->newValue("Entities Scripting Provider unavailable"), "InternalError"), ScriptValue()); return false; } return true; } -bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, ScriptValuePointer handler) { +bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, const ScriptValue& handler) { auto client = DependencyManager::get(); auto request = client->createScriptStatusRequest(entityID); QPointer manager = _manager; @@ -1558,7 +1558,7 @@ bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, ScriptV details["status"] = EntityScriptStatus_::valueToKey(request->getStatus()).toLower(); details["errorInfo"] = request->getErrorInfo(); - ScriptValuePointer err, result; + ScriptValue err, result; if (!details["success"].toBool()) { if (!details.contains("message") && details.contains("errorInfo")) { details["message"] = details["errorInfo"]; @@ -1577,10 +1577,13 @@ bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, ScriptV return true; } -bool EntityScriptingInterface::queryPropertyMetadata(const QUuid& entityID, ScriptValuePointer property, ScriptValuePointer scopeOrCallback, ScriptValuePointer methodOrName) { - auto name = property->toString(); +bool EntityScriptingInterface::queryPropertyMetadata(const QUuid& entityID, + const ScriptValue& property, + const ScriptValue& scopeOrCallback, + const ScriptValue& methodOrName) { + auto name = property.toString(); auto handler = makeScopedHandlerObject(scopeOrCallback, methodOrName); - QPointer manager = handler->engine()->manager(); + QPointer manager = handler.engine()->manager(); if (!manager) { qCDebug(entities) << "queryPropertyMetadata without detectable script manager" << entityID << name; return false; @@ -1591,7 +1594,7 @@ bool EntityScriptingInterface::queryPropertyMetadata(const QUuid& entityID, Scri qDebug() << "queryPropertyMetadata -- engine destroyed!" << (!engine ? "nullptr" : "engine"); }); #endif - if (!handler->property("callback")->isFunction()) { + if (!handler.property("callback").isFunction()) { qDebug() << "!handler.callback.isFunction" << manager; engine->raiseException(engine->makeError(engine->newValue("callback is not a function"), "TypeError")); return false; @@ -1622,11 +1625,11 @@ bool EntityScriptingInterface::queryPropertyMetadata(const QUuid& entityID, Scri } } -bool EntityScriptingInterface::getServerScriptStatus(const QUuid& entityID, ScriptValuePointer callback) { +bool EntityScriptingInterface::getServerScriptStatus(const QUuid& entityID, const ScriptValue& callback) { auto client = DependencyManager::get(); auto request = client->createScriptStatusRequest(entityID); - auto engine = callback->engine(); + auto engine = callback.engine(); auto manager = engine->manager(); if (!manager) { engine->raiseException(engine->makeError(engine->newValue("This script does not belong to a ScriptManager"))); @@ -1636,9 +1639,9 @@ bool EntityScriptingInterface::getServerScriptStatus(const QUuid& entityID, Scri connect(request, &GetScriptStatusRequest::finished, manager, [callback](GetScriptStatusRequest* request) mutable { QString statusString = EntityScriptStatus_::valueToKey(request->getStatus()); - auto engine = callback->engine(); + auto engine = callback.engine(); ScriptValueList args { engine->newValue(request->getResponseReceived()), engine->newValue(request->getIsRunning()), engine->newValue(statusString.toLower()), engine->newValue(request->getErrorInfo()) }; - callback->call(ScriptValuePointer(), args); + callback.call(ScriptValue(), args); request->deleteLater(); }); request->start(); @@ -1669,40 +1672,40 @@ bool EntityScriptingInterface::getDrawZoneBoundaries() const { return ZoneEntityItem::getDrawZoneBoundaries(); } -ScriptValuePointer RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, const RayToEntityIntersectionResult& value) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("intersects", value.intersects); - obj->setProperty("accurate", value.accurate); - ScriptValuePointer entityItemValue = EntityItemIDtoScriptValue(engine, value.entityID); - obj->setProperty("entityID", entityItemValue); - obj->setProperty("distance", value.distance); - obj->setProperty("face", boxFaceToString(value.face)); - - ScriptValuePointer intersection = vec3ToScriptValue(engine, value.intersection); - obj->setProperty("intersection", intersection); - ScriptValuePointer surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); - obj->setProperty("surfaceNormal", surfaceNormal); - obj->setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); +ScriptValue RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, const RayToEntityIntersectionResult& value) { + ScriptValue obj = engine->newObject(); + obj.setProperty("intersects", value.intersects); + obj.setProperty("accurate", value.accurate); + ScriptValue entityItemValue = EntityItemIDtoScriptValue(engine, value.entityID); + obj.setProperty("entityID", entityItemValue); + obj.setProperty("distance", value.distance); + obj.setProperty("face", boxFaceToString(value.face)); + + ScriptValue intersection = vec3ToScriptValue(engine, value.intersection); + obj.setProperty("intersection", intersection); + ScriptValue surfaceNormal = vec3ToScriptValue(engine, value.surfaceNormal); + obj.setProperty("surfaceNormal", surfaceNormal); + obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); return obj; } -void RayToEntityIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToEntityIntersectionResult& value) { - value.intersects = object->property("intersects")->toVariant().toBool(); - value.accurate = object->property("accurate")->toVariant().toBool(); - ScriptValuePointer entityIDValue = object->property("entityID"); +void RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& value) { + value.intersects = object.property("intersects").toVariant().toBool(); + value.accurate = object.property("accurate").toVariant().toBool(); + ScriptValue entityIDValue = object.property("entityID"); quuidFromScriptValue(entityIDValue, value.entityID); - value.distance = object->property("distance")->toVariant().toFloat(); - value.face = boxFaceFromString(object->property("face")->toVariant().toString()); + value.distance = object.property("distance").toVariant().toFloat(); + value.face = boxFaceFromString(object.property("face").toVariant().toString()); - ScriptValuePointer intersection = object->property("intersection"); - if (intersection->isValid()) { + ScriptValue intersection = object.property("intersection"); + if (intersection.isValid()) { vec3FromScriptValue(intersection, value.intersection); } - ScriptValuePointer surfaceNormal = object->property("surfaceNormal"); - if (surfaceNormal->isValid()) { + ScriptValue surfaceNormal = object.property("surfaceNormal"); + if (surfaceNormal.isValid()) { vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } - value.extraInfo = object->property("extraInfo")->toVariant().toMap(); + value.extraInfo = object.property("extraInfo").toVariant().toMap(); } bool EntityScriptingInterface::polyVoxWorker(QUuid entityID, std::function actor) { @@ -2423,15 +2426,15 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons return aaBox.findCapsulePenetration(start, end, radius, penetration); } -void EntityScriptingInterface::getMeshes(const QUuid& entityID, ScriptValuePointer callback) { +void EntityScriptingInterface::getMeshes(const QUuid& entityID, const ScriptValue& callback) { PROFILE_RANGE(script_entities, __FUNCTION__); - auto engine = callback->engine(); + auto engine = callback.engine(); EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::getMeshes no entity with ID" << entityID; ScriptValueList args { engine->undefinedValue(), false }; - callback->call(ScriptValuePointer(), args); + callback.call(ScriptValue(), args); return; } @@ -2439,12 +2442,12 @@ void EntityScriptingInterface::getMeshes(const QUuid& entityID, ScriptValuePoint bool success = entity->getMeshes(result); if (success) { - ScriptValuePointer resultAsScriptValue = meshesToScriptValue(engine.data(), result); + ScriptValue resultAsScriptValue = meshesToScriptValue(engine.data(), result); ScriptValueList args{ resultAsScriptValue, engine->newValue(true) }; - callback->call(ScriptValuePointer(), args); + callback.call(ScriptValue(), args); } else { ScriptValueList args { engine->undefinedValue(), engine->newValue(false) }; - callback->call(ScriptValuePointer(), args); + callback.call(ScriptValue(), args); } } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 854ce4943c4..5e5f83a5c64 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -28,6 +28,7 @@ #include "PointerEvent.h" #include #include +#include #include "PolyVoxEntityItem.h" #include "LineEntityItem.h" @@ -42,8 +43,6 @@ class EntityTree; class MeshProxy; class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; extern const QString GRABBABLE_USER_DATA; extern const QString NOT_GRABBABLE_USER_DATA; @@ -55,8 +54,8 @@ extern const QString NOT_GRABBABLE_USER_DATA; class EntityPropertyMetadataRequest { public: EntityPropertyMetadataRequest(ScriptManager* manager) : _manager(manager == nullptr ? nullptr : manager){}; - bool script(EntityItemID entityID, ScriptValuePointer handler); - bool serverScripts(EntityItemID entityID, ScriptValuePointer handler); + bool script(EntityItemID entityID, const ScriptValue& handler); + bool serverScripts(EntityItemID entityID, const ScriptValue& handler); private: QPointer _manager; }; @@ -89,8 +88,8 @@ class RayToEntityIntersectionResult { QVariantMap extraInfo; }; Q_DECLARE_METATYPE(RayToEntityIntersectionResult) -ScriptValuePointer RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, const RayToEntityIntersectionResult& results); -void RayToEntityIntersectionResultFromScriptValue(const ScriptValuePointer& object, RayToEntityIntersectionResult& results); +ScriptValue RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, const RayToEntityIntersectionResult& results); +void RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& results); class ParabolaToEntityIntersectionResult { public: @@ -212,8 +211,8 @@ class EntityScriptingInterface : public OctreeScriptingInterface, public Depende * var propertySets = Entities.getMultipleEntityProperties(entityIDs, "name"); * print("Nearby entity names: " + JSON.stringify(propertySets)); */ - static ScriptValuePointer getMultipleEntityProperties(ScriptContext* context, ScriptEngine* engine); - ScriptValuePointer getMultipleEntityPropertiesInternal(ScriptEngine* engine, QVector entityIDs, const ScriptValuePointer& extendedDesiredProperties); + static ScriptValue getMultipleEntityProperties(ScriptContext* context, ScriptEngine* engine); + ScriptValue getMultipleEntityPropertiesInternal(ScriptEngine* engine, QVector entityIDs, const ScriptValue& extendedDesiredProperties); QUuid addEntityInternal(const EntityItemProperties& properties, entity::HostType entityHostType); @@ -838,7 +837,7 @@ public slots: /// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate /// will be false. Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false, - const ScriptValuePointer& entityIdsToInclude = ScriptValuePointer(), const ScriptValuePointer& entityIdsToDiscard = ScriptValuePointer(), + const ScriptValue& entityIdsToInclude = ScriptValue(), const ScriptValue& entityIdsToDiscard = ScriptValue(), bool visibleOnly = false, bool collidableOnly = false) const; /*@jsdoc @@ -867,7 +866,7 @@ public slots: * @param {string} errorInfo - "" if there is a server entity script running, otherwise it may contain extra * information on the error. */ - Q_INVOKABLE bool getServerScriptStatus(const QUuid& entityID, ScriptValuePointer callback); + Q_INVOKABLE bool getServerScriptStatus(const QUuid& entityID, const ScriptValue& callback); /*@jsdoc * Gets metadata for certain entity properties such as script and serverScripts. @@ -897,8 +896,8 @@ public slots: * @param {object} result - The metadata for the requested entity property if there was no error, otherwise * undefined. */ - Q_INVOKABLE bool queryPropertyMetadata(const QUuid& entityID, ScriptValuePointer property, ScriptValuePointer scopeOrCallback, - ScriptValuePointer methodOrName = ScriptValuePointer()); + Q_INVOKABLE bool queryPropertyMetadata(const QUuid& entityID, const ScriptValue& property, const ScriptValue& scopeOrCallback, + const ScriptValue& methodOrName = ScriptValue()); /*@jsdoc @@ -1911,7 +1910,7 @@ public slots: * {@link Graphics} API instead. */ // FIXME move to a renderable entity interface - Q_INVOKABLE void getMeshes(const QUuid& entityID, ScriptValuePointer callback); + Q_INVOKABLE void getMeshes(const QUuid& entityID, const ScriptValue& callback); /*@jsdoc * Gets the object to world transform, excluding scale, of an entity. diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 38dda4932c8..53724920361 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -3089,7 +3089,7 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { // map will have a top-level list keyed as "Entities". This will be extracted // and iterated over. Each member of this list is converted to a QVariantMap, then - // to a ScriptValuePointer, and then to EntityItemProperties. These properties are used + // to a ScriptValue, and then to EntityItemProperties. These properties are used // to add the new entity to the EntityTree. QVariantList entitiesQList = map["Entities"].toList(); ScriptEnginePointer scriptEngine = newScriptEngine(); @@ -3103,7 +3103,7 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { bool success = true; foreach (QVariant entityVariant, entitiesQList) { - // QVariantMap --> ScriptValuePointer --> EntityItemProperties --> Entity + // QVariantMap --> ScriptValue --> EntityItemProperties --> Entity QVariantMap entityMap = entityVariant.toMap(); // handle parentJointName for wearables @@ -3116,7 +3116,7 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { " mapped it to parentJointIndex " << entityMap["parentJointIndex"].toInt(); } - ScriptValuePointer entityScriptValue = variantMapToScriptValue(entityMap, *scriptEngine); + ScriptValue entityScriptValue = variantMapToScriptValue(entityMap, *scriptEngine); EntityItemProperties properties; EntityItemPropertiesFromScriptValueIgnoreReadOnly(entityScriptValue, properties); diff --git a/libraries/entities/src/GrabPropertyGroup.cpp b/libraries/entities/src/GrabPropertyGroup.cpp index f18d1c2c4a2..10572dbcb8a 100644 --- a/libraries/entities/src/GrabPropertyGroup.cpp +++ b/libraries/entities/src/GrabPropertyGroup.cpp @@ -16,7 +16,7 @@ #include "EntityItemProperties.h" #include "EntityItemPropertiesMacros.h" -void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, +void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable); @@ -43,7 +43,7 @@ void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProp } -void GrabPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void GrabPropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabbable, bool, setGrabbable); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabKinematic, bool, setGrabKinematic); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabFollowsController, bool, setGrabFollowsController); diff --git a/libraries/entities/src/GrabPropertyGroup.h b/libraries/entities/src/GrabPropertyGroup.h index a6577edda26..ebf0175ea33 100644 --- a/libraries/entities/src/GrabPropertyGroup.h +++ b/libraries/entities/src/GrabPropertyGroup.h @@ -16,8 +16,6 @@ #include -#include - #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" @@ -26,7 +24,6 @@ class EncodeBitstreamParams; class OctreePacketData; class ReadBitstreamToTreeParams; class ScriptValue; -using ScriptValuePointer = QSharedPointer; static const bool INITIAL_GRABBABLE { true }; static const bool INITIAL_KINEMATIC { true }; @@ -74,10 +71,10 @@ static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_OFFSET { glm::vec3(0.0f) }; class GrabPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const GrabPropertyGroup& other); diff --git a/libraries/entities/src/HazePropertyGroup.cpp b/libraries/entities/src/HazePropertyGroup.cpp index d9b939babcc..04595789e59 100644 --- a/libraries/entities/src/HazePropertyGroup.cpp +++ b/libraries/entities/src/HazePropertyGroup.cpp @@ -16,7 +16,7 @@ #include "EntityItemProperties.h" #include "EntityItemPropertiesMacros.h" -void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_RANGE, Haze, haze, HazeRange, hazeRange); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_HAZE_COLOR, Haze, haze, HazeColor, hazeColor, u8vec3Color); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_HAZE_GLARE_COLOR, Haze, haze, HazeGlareColor, hazeGlareColor, u8vec3Color); @@ -34,7 +34,7 @@ void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProp COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude); } -void HazePropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void HazePropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeRange, float, setHazeRange); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeColor, u8vec3Color, setHazeColor); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeGlareColor, u8vec3Color, setHazeGlareColor); diff --git a/libraries/entities/src/HazePropertyGroup.h b/libraries/entities/src/HazePropertyGroup.h index 208766fde0f..249d4c65bce 100644 --- a/libraries/entities/src/HazePropertyGroup.h +++ b/libraries/entities/src/HazePropertyGroup.h @@ -16,8 +16,6 @@ #include -#include - #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" @@ -28,7 +26,6 @@ class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; static const float INITIAL_HAZE_RANGE{ 1000.0f }; static const glm::u8vec3 initialHazeGlareColor { 255, 229, 179 }; @@ -79,10 +76,10 @@ static const float INITIAL_KEY_LIGHT_ALTITUDE{ 200.0f }; class HazePropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const HazePropertyGroup& other); diff --git a/libraries/entities/src/KeyLightPropertyGroup.cpp b/libraries/entities/src/KeyLightPropertyGroup.cpp index f688b47af36..b96f34d07c0 100644 --- a/libraries/entities/src/KeyLightPropertyGroup.cpp +++ b/libraries/entities/src/KeyLightPropertyGroup.cpp @@ -25,7 +25,7 @@ const bool KeyLightPropertyGroup::DEFAULT_KEYLIGHT_CAST_SHADOWS { false }; const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_SHADOW_BIAS { 0.5f }; const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_SHADOW_MAX_DISTANCE { 40.0f }; -void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, +void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_KEYLIGHT_COLOR, KeyLight, keyLight, Color, color, u8vec3Color); @@ -36,7 +36,7 @@ void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desired COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, KeyLight, keyLight, ShadowMaxDistance, shadowMaxDistance); } -void KeyLightPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void KeyLightPropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, color, u8vec3Color, setColor); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, intensity, float, setIntensity); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, direction, vec3, setDirection); diff --git a/libraries/entities/src/KeyLightPropertyGroup.h b/libraries/entities/src/KeyLightPropertyGroup.h index b88db49798e..b04f76a0980 100644 --- a/libraries/entities/src/KeyLightPropertyGroup.h +++ b/libraries/entities/src/KeyLightPropertyGroup.h @@ -17,7 +17,6 @@ #include -#include #include "EntityItemPropertiesMacros.h" #include "PropertyGroup.h" @@ -28,7 +27,6 @@ class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * A key light is defined by the following properties: @@ -48,10 +46,10 @@ using ScriptValuePointer = QSharedPointer; class KeyLightPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const KeyLightPropertyGroup& other); diff --git a/libraries/entities/src/PropertyGroup.h b/libraries/entities/src/PropertyGroup.h index 9d74388caac..68f3bfb5698 100644 --- a/libraries/entities/src/PropertyGroup.h +++ b/libraries/entities/src/PropertyGroup.h @@ -12,8 +12,6 @@ #ifndef hifi_PropertyGroup_h #define hifi_PropertyGroup_h -#include - #include #include "EntityPropertyFlags.h" @@ -26,7 +24,6 @@ class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr; @@ -35,8 +32,8 @@ class PropertyGroup { virtual ~PropertyGroup() = default; // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) = 0; + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const = 0; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) = 0; virtual void debugDump() const { } virtual void listChangedProperties(QList& out) { } diff --git a/libraries/entities/src/PulsePropertyGroup.cpp b/libraries/entities/src/PulsePropertyGroup.cpp index 7db361df6f5..b5ebd0cb2e8 100644 --- a/libraries/entities/src/PulsePropertyGroup.cpp +++ b/libraries/entities/src/PulsePropertyGroup.cpp @@ -57,7 +57,7 @@ void PulsePropertyGroup::setAlphaModeFromString(const QString& pulseMode) { } } -void PulsePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, +void PulsePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_PULSE_MIN, Pulse, pulse, Min, min); @@ -67,7 +67,7 @@ void PulsePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredPro COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PULSE_ALPHA_MODE, Pulse, pulse, AlphaMode, alphaMode, getAlphaModeAsString); } -void PulsePropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void PulsePropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, min, float, setMin); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, max, float, setMax); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, period, float, setPeriod); diff --git a/libraries/entities/src/PulsePropertyGroup.h b/libraries/entities/src/PulsePropertyGroup.h index 9f9bc921506..58452fdeead 100644 --- a/libraries/entities/src/PulsePropertyGroup.h +++ b/libraries/entities/src/PulsePropertyGroup.h @@ -13,8 +13,6 @@ #include -#include - #include #include "PropertyGroup.h" @@ -26,7 +24,6 @@ class OctreePacketData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * A color and alpha pulse that an entity may have. @@ -43,10 +40,10 @@ using ScriptValuePointer = QSharedPointer; class PulsePropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const PulsePropertyGroup& other); diff --git a/libraries/entities/src/RecurseOctreeToJSONOperator.cpp b/libraries/entities/src/RecurseOctreeToJSONOperator.cpp index 7e91a8d0482..855085cbca4 100644 --- a/libraries/entities/src/RecurseOctreeToJSONOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToJSONOperator.cpp @@ -35,7 +35,7 @@ void RecurseOctreeToJSONOperator::processEntity(const EntityItemPointer& entity) return; // we weren't able to resolve a parent from _parentID, so don't save this entity. } - ScriptValuePointer qScriptValues = _skipDefaults + ScriptValue qScriptValues = _skipDefaults ? EntityItemNonDefaultPropertiesToScriptValue(_engine, entity->getProperties()) : EntityItemPropertiesToScriptValue(_engine, entity->getProperties()); @@ -46,6 +46,6 @@ void RecurseOctreeToJSONOperator::processEntity(const EntityItemPointer& entity) _json += "\n "; // Override default toString(): - qScriptValues->setProperty("toString", _toStringMethod); - _json += qScriptValues->toString(); + qScriptValues.setProperty("toString", _toStringMethod); + _json += qScriptValues.toString(); } diff --git a/libraries/entities/src/RecurseOctreeToJSONOperator.h b/libraries/entities/src/RecurseOctreeToJSONOperator.h index 4f4fce5b425..09d383d5a72 100644 --- a/libraries/entities/src/RecurseOctreeToJSONOperator.h +++ b/libraries/entities/src/RecurseOctreeToJSONOperator.h @@ -11,11 +11,9 @@ #include "EntityTree.h" -#include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class RecurseOctreeToJSONOperator : public RecurseOctreeOperator { public: @@ -30,7 +28,7 @@ class RecurseOctreeToJSONOperator : public RecurseOctreeOperator { void processEntity(const EntityItemPointer& entity); ScriptEngine* _engine; - ScriptValuePointer _toStringMethod; + ScriptValue _toStringMethod; QString _json; const bool _skipDefaults; diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.cpp b/libraries/entities/src/RecurseOctreeToMapOperator.cpp index e8f1a483f89..deac281d49b 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToMapOperator.cpp @@ -57,7 +57,7 @@ bool RecurseOctreeToMapOperator::postRecursion(const OctreeElementPointer& eleme } EntityItemProperties properties = entityItem->getProperties(); - ScriptValuePointer qScriptValues; + ScriptValue qScriptValues; if (_skipDefaultValues) { qScriptValues = EntityItemNonDefaultPropertiesToScriptValue(_engine, properties); } else { @@ -71,11 +71,11 @@ bool RecurseOctreeToMapOperator::postRecursion(const OctreeElementPointer& eleme auto jointNames = _myAvatar->getJointNames(); auto parentJointIndex = entityItem->getParentJointIndex(); if (parentJointIndex < jointNames.count()) { - qScriptValues->setProperty("parentJointName", jointNames.at(parentJointIndex)); + qScriptValues.setProperty("parentJointName", jointNames.at(parentJointIndex)); } } - entitiesQList << qScriptValues->toVariant(); + entitiesQList << qScriptValues.toVariant(); }); _map["Entities"] = entitiesQList; diff --git a/libraries/entities/src/RingGizmoPropertyGroup.cpp b/libraries/entities/src/RingGizmoPropertyGroup.cpp index 1dcc443609f..b9bb3a2b7e7 100644 --- a/libraries/entities/src/RingGizmoPropertyGroup.cpp +++ b/libraries/entities/src/RingGizmoPropertyGroup.cpp @@ -20,7 +20,7 @@ const float RingGizmoPropertyGroup::MAX_ALPHA = 1.0f; const float RingGizmoPropertyGroup::MIN_RADIUS = 0.0f; const float RingGizmoPropertyGroup::MAX_RADIUS = 0.5f; -void RingGizmoPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, +void RingGizmoPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_START_ANGLE, Ring, ring, StartAngle, startAngle); @@ -46,7 +46,7 @@ void RingGizmoPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_MINOR_TICK_MARKS_COLOR, Ring, ring, MinorTickMarksColor, minorTickMarksColor, u8vec3Color); } -void RingGizmoPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void RingGizmoPropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, startAngle, float, setStartAngle); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, endAngle, float, setEndAngle); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, innerRadius, float, setInnerRadius); diff --git a/libraries/entities/src/RingGizmoPropertyGroup.h b/libraries/entities/src/RingGizmoPropertyGroup.h index ca28b222186..d34f01c9b06 100644 --- a/libraries/entities/src/RingGizmoPropertyGroup.h +++ b/libraries/entities/src/RingGizmoPropertyGroup.h @@ -11,8 +11,6 @@ #include -#include - #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" #include "EntityItemPropertiesDefaults.h" @@ -23,7 +21,6 @@ class OctreePacketData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; using u8vec3Color = glm::u8vec3; @@ -59,10 +56,10 @@ using u8vec3Color = glm::u8vec3; class RingGizmoPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const RingGizmoPropertyGroup& other); diff --git a/libraries/entities/src/SkyboxPropertyGroup.cpp b/libraries/entities/src/SkyboxPropertyGroup.cpp index 4cd16c75791..43ffc878f4c 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.cpp +++ b/libraries/entities/src/SkyboxPropertyGroup.cpp @@ -18,12 +18,12 @@ const glm::u8vec3 SkyboxPropertyGroup::DEFAULT_COLOR = { 0, 0, 0 }; -void SkyboxPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { +void SkyboxPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color, u8vec3Color); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_SKYBOX_URL, Skybox, skybox, URL, url); } -void SkyboxPropertyGroup::copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) { +void SkyboxPropertyGroup::copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) { COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(skybox, color, u8vec3Color, setColor); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(skybox, url, QString, setURL); } diff --git a/libraries/entities/src/SkyboxPropertyGroup.h b/libraries/entities/src/SkyboxPropertyGroup.h index c95e92c7b33..89b2016802c 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.h +++ b/libraries/entities/src/SkyboxPropertyGroup.h @@ -16,8 +16,6 @@ #include -#include - #include #include "PropertyGroup.h" @@ -30,7 +28,6 @@ class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; class ScriptEngine; class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * A skybox is defined by the following properties: @@ -42,10 +39,10 @@ using ScriptValuePointer = QSharedPointer; class SkyboxPropertyGroup : public PropertyGroup { public: // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValuePointer& properties, + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const override; - virtual void copyFromScriptValue(const ScriptValuePointer& object, bool& _defaultSettings) override; + virtual void copyFromScriptValue(const ScriptValue& object, bool& _defaultSettings) override; void merge(const SkyboxPropertyGroup& other); diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index 08f531bdb29..eedeae2a3d7 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -319,14 +319,14 @@ namespace scriptable { scriptRegisterSequenceMetaType>>(engine); return scriptRegisterMetaType>( engine, - [](ScriptEngine* engine, const QPointer& object) -> ScriptValuePointer { + [](ScriptEngine* engine, const QPointer& object) -> ScriptValue { if (!object) { return engine->nullValue(); } return engine->newQObject(object, ScriptEngine::QtOwnership, ScriptEngine::AutoCreateDynamicProperties); }, - [](const ScriptValuePointer& value, QPointer& out) { - auto obj = value->toQObject(); + [](const ScriptValue& value, QPointer& out) { + auto obj = value.toQObject(); #ifdef SCRIPTABLE_MESH_DEBUG qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString(); #endif @@ -348,11 +348,11 @@ namespace scriptable { ); } - ScriptValuePointer qVectorScriptableMaterialLayerToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue qVectorScriptableMaterialLayerToScriptValue(ScriptEngine* engine, const QVector& vector) { return scriptValueFromSequence(engine, vector); } - void qVectorScriptableMaterialLayerFromScriptValue(const ScriptValuePointer& array, QVector& result) { + void qVectorScriptableMaterialLayerFromScriptValue(const ScriptValue& array, QVector& result) { scriptValueToSequence(array, result); } @@ -470,197 +470,197 @@ namespace scriptable { * @property {boolean} defaultFallthrough - true if all properties fall through to the material below unless * they are set, false if properties respect their individual fall-through settings. */ - ScriptValuePointer scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("name", material.name); - obj->setProperty("model", material.model); + ScriptValue scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material) { + ScriptValue obj = engine->newObject(); + obj.setProperty("name", material.name); + obj.setProperty("model", material.model); bool hasPropertyFallthroughs = !material.propertyFallthroughs.empty(); - const ScriptValuePointer FALLTHROUGH(engine->newValue("fallthrough")); + const ScriptValue FALLTHROUGH(engine->newValue("fallthrough")); if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_VAL_BIT)) { - obj->setProperty("opacity", FALLTHROUGH); + obj.setProperty("opacity", FALLTHROUGH); } else if (material.key.isTranslucentFactor()) { - obj->setProperty("opacity", material.opacity); + obj.setProperty("opacity", material.opacity); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_VAL_BIT)) { - obj->setProperty("albedo", FALLTHROUGH); + obj.setProperty("albedo", FALLTHROUGH); } else if (material.key.isAlbedo()) { - obj->setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo)); + obj.setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo)); } if (material.model.toStdString() == graphics::Material::HIFI_PBR) { if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_CUTOFF_VAL_BIT)) { - obj->setProperty("opacityCutoff", FALLTHROUGH); + obj.setProperty("opacityCutoff", FALLTHROUGH); } else if (material.key.isOpacityCutoff()) { - obj->setProperty("opacityCutoff", material.opacityCutoff); + obj.setProperty("opacityCutoff", material.opacityCutoff); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_MAP_MODE_BIT)) { - obj->setProperty("opacityMapMode", FALLTHROUGH); + obj.setProperty("opacityMapMode", FALLTHROUGH); } else if (material.key.isOpacityMapMode()) { - obj->setProperty("opacityMapMode", material.opacityMapMode); + obj.setProperty("opacityMapMode", material.opacityMapMode); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT)) { - obj->setProperty("roughness", FALLTHROUGH); + obj.setProperty("roughness", FALLTHROUGH); } else if (material.key.isGlossy()) { - obj->setProperty("roughness", material.roughness); + obj.setProperty("roughness", material.roughness); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT)) { - obj->setProperty("metallic", FALLTHROUGH); + obj.setProperty("metallic", FALLTHROUGH); } else if (material.key.isMetallic()) { - obj->setProperty("metallic", material.metallic); + obj.setProperty("metallic", material.metallic); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT)) { - obj->setProperty("scattering", FALLTHROUGH); + obj.setProperty("scattering", FALLTHROUGH); } else if (material.key.isScattering()) { - obj->setProperty("scattering", material.scattering); + obj.setProperty("scattering", material.scattering); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT)) { - obj->setProperty("unlit", FALLTHROUGH); + obj.setProperty("unlit", FALLTHROUGH); } else if (material.key.isUnlit()) { - obj->setProperty("unlit", material.unlit); + obj.setProperty("unlit", material.unlit); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT)) { - obj->setProperty("emissive", FALLTHROUGH); + obj.setProperty("emissive", FALLTHROUGH); } else if (material.key.isEmissive()) { - obj->setProperty("emissive", vec3ColorToScriptValue(engine, material.emissive)); + obj.setProperty("emissive", vec3ColorToScriptValue(engine, material.emissive)); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_MAP_BIT)) { - obj->setProperty("emissiveMap", FALLTHROUGH); + obj.setProperty("emissiveMap", FALLTHROUGH); } else if (!material.emissiveMap.isEmpty()) { - obj->setProperty("emissiveMap", material.emissiveMap); + obj.setProperty("emissiveMap", material.emissiveMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_MAP_BIT)) { - obj->setProperty("albedoMap", FALLTHROUGH); + obj.setProperty("albedoMap", FALLTHROUGH); } else if (!material.albedoMap.isEmpty()) { - obj->setProperty("albedoMap", material.albedoMap); + obj.setProperty("albedoMap", material.albedoMap); } if (!material.opacityMap.isEmpty()) { - obj->setProperty("opacityMap", material.opacityMap); + obj.setProperty("opacityMap", material.opacityMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT)) { - obj->setProperty("occlusionMap", FALLTHROUGH); + obj.setProperty("occlusionMap", FALLTHROUGH); } else if (!material.occlusionMap.isEmpty()) { - obj->setProperty("occlusionMap", material.occlusionMap); + obj.setProperty("occlusionMap", material.occlusionMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::LIGHT_MAP_BIT)) { - obj->setProperty("lightMap", FALLTHROUGH); + obj.setProperty("lightMap", FALLTHROUGH); } else if (!material.lightMap.isEmpty()) { - obj->setProperty("lightMap", material.lightMap); + obj.setProperty("lightMap", material.lightMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT)) { - obj->setProperty("scatteringMap", FALLTHROUGH); + obj.setProperty("scatteringMap", FALLTHROUGH); } else if (!material.scatteringMap.isEmpty()) { - obj->setProperty("scatteringMap", material.scatteringMap); + obj.setProperty("scatteringMap", material.scatteringMap); } // Only set one of each of these if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) { - obj->setProperty("metallicMap", FALLTHROUGH); + obj.setProperty("metallicMap", FALLTHROUGH); } else if (!material.metallicMap.isEmpty()) { - obj->setProperty("metallicMap", material.metallicMap); + obj.setProperty("metallicMap", material.metallicMap); } else if (!material.specularMap.isEmpty()) { - obj->setProperty("specularMap", material.specularMap); + obj.setProperty("specularMap", material.specularMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::ROUGHNESS_MAP_BIT)) { - obj->setProperty("roughnessMap", FALLTHROUGH); + obj.setProperty("roughnessMap", FALLTHROUGH); } else if (!material.roughnessMap.isEmpty()) { - obj->setProperty("roughnessMap", material.roughnessMap); + obj.setProperty("roughnessMap", material.roughnessMap); } else if (!material.glossMap.isEmpty()) { - obj->setProperty("glossMap", material.glossMap); + obj.setProperty("glossMap", material.glossMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::NORMAL_MAP_BIT)) { - obj->setProperty("normalMap", FALLTHROUGH); + obj.setProperty("normalMap", FALLTHROUGH); } else if (!material.normalMap.isEmpty()) { - obj->setProperty("normalMap", material.normalMap); + obj.setProperty("normalMap", material.normalMap); } else if (!material.bumpMap.isEmpty()) { - obj->setProperty("bumpMap", material.bumpMap); + obj.setProperty("bumpMap", material.bumpMap); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::TEXCOORDTRANSFORM0)) { - obj->setProperty("texCoordTransform0", FALLTHROUGH); + obj.setProperty("texCoordTransform0", FALLTHROUGH); } else if (material.texCoordTransforms[0] != mat4()) { - obj->setProperty("texCoordTransform0", mat4toScriptValue(engine, material.texCoordTransforms[0])); + obj.setProperty("texCoordTransform0", mat4toScriptValue(engine, material.texCoordTransforms[0])); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::TEXCOORDTRANSFORM1)) { - obj->setProperty("texCoordTransform1", FALLTHROUGH); + obj.setProperty("texCoordTransform1", FALLTHROUGH); } else if (material.texCoordTransforms[1] != mat4()) { - obj->setProperty("texCoordTransform1", mat4toScriptValue(engine, material.texCoordTransforms[1])); + obj.setProperty("texCoordTransform1", mat4toScriptValue(engine, material.texCoordTransforms[1])); } // These need to be implemented, but set the fallthrough for now if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::LIGHTMAP_PARAMS)) { - obj->setProperty("lightmapParams", FALLTHROUGH); + obj.setProperty("lightmapParams", FALLTHROUGH); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::MATERIAL_PARAMS)) { - obj->setProperty("materialParams", FALLTHROUGH); + obj.setProperty("materialParams", FALLTHROUGH); } if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::CULL_FACE_MODE)) { - obj->setProperty("cullFaceMode", FALLTHROUGH); + obj.setProperty("cullFaceMode", FALLTHROUGH); } else if (!material.cullFaceMode.isEmpty()) { - obj->setProperty("cullFaceMode", material.cullFaceMode); + obj.setProperty("cullFaceMode", material.cullFaceMode); } } else if (material.model.toStdString() == graphics::Material::HIFI_SHADER_SIMPLE) { - obj->setProperty("procedural", material.procedural); + obj.setProperty("procedural", material.procedural); } - obj->setProperty("defaultFallthrough", material.defaultFallthrough); + obj.setProperty("defaultFallthrough", material.defaultFallthrough); return obj; } - void scriptableMaterialFromScriptValue(const ScriptValuePointer &object, scriptable::ScriptableMaterial& material) { - // No need to convert from ScriptValuePointer to ScriptableMaterial + void scriptableMaterialFromScriptValue(const ScriptValue &object, scriptable::ScriptableMaterial& material) { + // No need to convert from ScriptValue to ScriptableMaterial } - ScriptValuePointer scriptableMaterialLayerToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("material", scriptableMaterialToScriptValue(engine, materialLayer.material)); - obj->setProperty("priority", materialLayer.priority); + ScriptValue scriptableMaterialLayerToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) { + ScriptValue obj = engine->newObject(); + obj.setProperty("material", scriptableMaterialToScriptValue(engine, materialLayer.material)); + obj.setProperty("priority", materialLayer.priority); return obj; } - void scriptableMaterialLayerFromScriptValue(const ScriptValuePointer &object, scriptable::ScriptableMaterialLayer& materialLayer) { - // No need to convert from ScriptValuePointer to ScriptableMaterialLayer + void scriptableMaterialLayerFromScriptValue(const ScriptValue &object, scriptable::ScriptableMaterialLayer& materialLayer) { + // No need to convert from ScriptValue to ScriptableMaterialLayer } - ScriptValuePointer multiMaterialMapToScriptValue(ScriptEngine* engine, const scriptable::MultiMaterialMap& map) { - ScriptValuePointer obj = engine->newObject(); + ScriptValue multiMaterialMapToScriptValue(ScriptEngine* engine, const scriptable::MultiMaterialMap& map) { + ScriptValue obj = engine->newObject(); for (auto key : map.keys()) { - obj->setProperty(key, qVectorScriptableMaterialLayerToScriptValue(engine, map[key])); + obj.setProperty(key, qVectorScriptableMaterialLayerToScriptValue(engine, map[key])); } return obj; } - void multiMaterialMapFromScriptValue(const ScriptValuePointer& map, scriptable::MultiMaterialMap& result) { - // No need to convert from ScriptValuePointer to MultiMaterialMap + void multiMaterialMapFromScriptValue(const ScriptValue& map, scriptable::MultiMaterialMap& result) { + // No need to convert from ScriptValue to MultiMaterialMap } template int registerDebugEnum(ScriptEngine* engine, const DebugEnums& debugEnums) { static const DebugEnums& instance = debugEnums; return scriptRegisterMetaType( engine, - [](ScriptEngine* engine, const T& topology) -> ScriptValuePointer { + [](ScriptEngine* engine, const T& topology) -> ScriptValue { return engine->newValue(instance.value(topology)); }, - [](const ScriptValuePointer& value, T& topology) { - topology = instance.key(value->toString()); + [](const ScriptValue& value, T& topology) { + topology = instance.key(value.toString()); } ); } diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h index 18f4a2d0daf..a2ffb9184b7 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h @@ -11,7 +11,6 @@ #ifndef hifi_GraphicsScriptingInterface_h #define hifi_GraphicsScriptingInterface_h -#include #include #include @@ -19,10 +18,9 @@ #include #include "RegisteredMetaTypes.h" #include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The Graphics API enables you to access and manipulate avatar, entity, and overlay models in the rendered scene. @@ -151,7 +149,7 @@ public slots: }; namespace scriptable { - ScriptValuePointer scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material); + ScriptValue scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material); }; Q_DECLARE_METATYPE(NestableType) diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp index 24ae3831206..e42d3ad86ae 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp @@ -10,9 +10,9 @@ #include #include #include -#include "ScriptContext.h" -#include "ScriptEngine.h" -#include "ScriptValue.h" +#include +#include +#include using buffer_helpers::glmVecToVariant; @@ -78,27 +78,27 @@ QVariant toVariant(const gpu::Element& element) { }; } -ScriptValuePointer jsBindCallback(ScriptValuePointer value) { - if (value->isObject() && value->property("callback")->isFunction()) { +ScriptValue jsBindCallback(const ScriptValue& value) { + if (value.isObject() && value.property("callback").isFunction()) { // value is already a bound callback return value; } - auto engine = value->engine(); + auto engine = value.engine(); auto context = engine ? engine->currentContext() : nullptr; auto length = context ? context->argumentCount() : 0; - ScriptValuePointer scope = context ? context->thisObject() : engine->nullValue(); - ScriptValuePointer method; + ScriptValue scope = context ? context->thisObject() : engine->nullValue(); + ScriptValue method; #ifdef SCRIPTABLE_MESH_DEBUG qCInfo(graphics_scripting) << "jsBindCallback" << engine << length << scope.toQObject() << method.toString(); #endif // find position in the incoming JS Function.arguments array (so we can test for the two-argument case) for (int i = 0; context && i < length; i++) { - if (context->argument(i)->strictlyEquals(value)) { + if (context->argument(i).strictlyEquals(value)) { method = context->argument(i+1); } } - if (method->isFunction() || method->isString()) { + if (method.isFunction() || method.isString()) { // interpret as `API.func(..., scope, function callback(){})` or `API.func(..., scope, "methodName")` scope = value; } else { @@ -114,7 +114,7 @@ ScriptValuePointer jsBindCallback(ScriptValuePointer value) { template T this_qobject_cast(ScriptEngine* engine) { auto context = engine ? engine->currentContext() : nullptr; - return scriptvalue_cast(context ? context->thisObject() : ScriptValuePointer::NullValue); + return scriptvalue_cast(context ? context->thisObject() : ScriptValue::NullValue); } QString toDebugString(QObject* tmp) { QString s; diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h index ec979045529..53b49d1bd34 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h @@ -1,17 +1,15 @@ #pragma once #include -#include #include #include #include #include #include #include +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class Extents; class AABox; @@ -27,12 +25,12 @@ namespace scriptable { QVariant toVariant(const glm::mat4& mat4); // helper that automatically resolves Qt-signal-like scoped callbacks - // ... C++ side: `void MyClass::asyncMethod(..., ScriptValuePointer callback)` + // ... C++ side: `void MyClass::asyncMethod(..., const ScriptValue& callback)` // ... JS side: // * `API.asyncMethod(..., function(){})` // * `API.asyncMethod(..., scope, function(){})` // * `API.asyncMethod(..., scope, "methodName")` - ScriptValuePointer jsBindCallback(ScriptValuePointer callback); + ScriptValue jsBindCallback(const ScriptValue& callback); // cast engine->thisObject() => C++ class instance template T this_qobject_cast(ScriptEngine* engine); diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp index f825e5c0ee5..f19e58eca9d 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp @@ -7,8 +7,6 @@ #include "ScriptableMesh.h" -#include - #include #include #include @@ -266,7 +264,7 @@ bool scriptable::ScriptableMesh::setVertexProperty(glm::uint32 vertexIndex, cons * @param {number} index - The vertex index. * @param {object} properties - The properties of the mesh, per {@link GraphicsMesh}. */ -glm::uint32 scriptable::ScriptableMesh::forEachVertex(ScriptValuePointer _callback) { +glm::uint32 scriptable::ScriptableMesh::forEachVertex(const ScriptValue& _callback) { auto mesh = getMeshPointer(); if (!mesh) { return 0; @@ -274,16 +272,16 @@ glm::uint32 scriptable::ScriptableMesh::forEachVertex(ScriptValuePointer _callba auto scopedHandler = jsBindCallback(_callback); // destructure so we can still invoke callback scoped, but with a custom signature (obj, i, jsMesh) - auto scope = scopedHandler->property("scope"); - auto callback = scopedHandler->property("callback"); - auto js = engine() ? engine() : scopedHandler->engine(); // cache value to avoid resolving each iteration + auto scope = scopedHandler.property("scope"); + auto callback = scopedHandler.property("callback"); + auto js = engine() ? engine() : scopedHandler.engine(); // cache value to avoid resolving each iteration if (!js) { return 0; } auto meshPart = js ? js->toScriptValue(getSelf()) : js->nullValue(); int numProcessed = 0; buffer_helpers::mesh::forEachVertex(mesh, [&](glm::uint32 index, const QVariantMap& values) { - auto result = callback->call(scope, { js->toScriptValue(values), js->newValue(index), meshPart }); + auto result = callback.call(scope, { js->toScriptValue(values), js->newValue(index), meshPart }); if (js->hasUncaughtException()) { js->currentContext()->throwValue(js->uncaughtException()); return false; @@ -304,7 +302,7 @@ glm::uint32 scriptable::ScriptableMesh::forEachVertex(ScriptValuePointer _callba * @returns {Object|boolean} The attribute values to update the vertex with, or * false to not update the vertex. */ -glm::uint32 scriptable::ScriptableMesh::updateVertexAttributes(ScriptValuePointer _callback) { +glm::uint32 scriptable::ScriptableMesh::updateVertexAttributes(const ScriptValue& _callback) { auto mesh = getMeshPointer(); if (!mesh) { return 0; @@ -312,9 +310,9 @@ glm::uint32 scriptable::ScriptableMesh::updateVertexAttributes(ScriptValuePointe auto scopedHandler = jsBindCallback(_callback); // destructure so we can still invoke callback scoped, but with a custom signature (obj, i, jsMesh) - auto scope = scopedHandler->property("scope"); - auto callback = scopedHandler->property("callback"); - auto js = engine() ? engine() : scopedHandler->engine(); // cache value to avoid resolving each iteration + auto scope = scopedHandler.property("scope"); + auto callback = scopedHandler.property("callback"); + auto js = engine() ? engine() : scopedHandler.engine(); // cache value to avoid resolving each iteration if (!js) { return 0; } @@ -323,23 +321,23 @@ glm::uint32 scriptable::ScriptableMesh::updateVertexAttributes(ScriptValuePointe auto attributeViews = buffer_helpers::mesh::getAllBufferViews(mesh); buffer_helpers::mesh::forEachVertex(mesh, [&](glm::uint32 index, const QVariantMap& values) { auto obj = js->toScriptValue(values); - auto result = callback->call(scope, { obj, js->newValue(index), meshPart }); + auto result = callback.call(scope, { obj, js->newValue(index), meshPart }); if (js->hasUncaughtException()) { js->currentContext()->throwValue(js->uncaughtException()); return false; } - if (result->isBool() && !result->toBool()) { + if (result.isBool() && !result.toBool()) { // bail without modifying data if user explicitly returns false return true; } - if (result->isObject() && !result->strictlyEquals(obj)) { + if (result.isObject() && !result.strictlyEquals(obj)) { // user returned a new object (ie: instead of modifying input properties) obj = result; } for (const auto& a : attributeViews) { - const auto& attribute = obj->property(a.first); - if (attribute->isValid()) { - buffer_helpers::setValue(a.second, index, attribute->toVariant()); + const auto& attribute = obj.property(a.first); + if (attribute.isValid()) { + buffer_helpers::setValue(a.second, index, attribute.toVariant()); } } numProcessed++; diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h index 213b58b2ad5..4a1419dd45a 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h @@ -20,7 +20,6 @@ #include #include #include -#include #include "GraphicsScriptingUtil.h" @@ -28,7 +27,6 @@ #include class ScriptValue; -using ScriptValuePointer = QSharedPointer; namespace scriptable { /*@jsdoc @@ -236,7 +234,7 @@ namespace scriptable { * @param {GraphicsMesh~updateVertexAttributesCallback} callback - The function to call for each vertex. * @returns {number} The number of vertices the callback was called for. */ - glm::uint32 updateVertexAttributes(ScriptValuePointer callback); + glm::uint32 updateVertexAttributes(const ScriptValue& callback); /*@jsdoc * Calls a function for each vertex. @@ -244,7 +242,7 @@ namespace scriptable { * @param {GraphicsMesh~forEachVertexCallback} callback - The function to call for each vertex. * @returns {number} The number of vertices the callback was called for. */ - glm::uint32 forEachVertex(ScriptValuePointer callback); + glm::uint32 forEachVertex(const ScriptValue& callback); /*@jsdoc * Checks if an index is valid and, optionally, that vertex has a particular attribute. diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp index d12dc0c60cc..eaad4799e0a 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp @@ -77,12 +77,12 @@ QVariantList scriptable::ScriptableMeshPart::queryVertexAttributes(QVariant sele return parentMesh->queryVertexAttributes(selector); } -glm::uint32 scriptable::ScriptableMeshPart::forEachVertex(ScriptValuePointer _callback) { +glm::uint32 scriptable::ScriptableMeshPart::forEachVertex(const ScriptValue& _callback) { // TODO: limit to vertices within the part's indexed range? return isValid() ? parentMesh->forEachVertex(_callback) : 0; } -glm::uint32 scriptable::ScriptableMeshPart::updateVertexAttributes(ScriptValuePointer _callback) { +glm::uint32 scriptable::ScriptableMeshPart::updateVertexAttributes(const ScriptValue& _callback) { // TODO: limit to vertices within the part's indexed range? return isValid() ? parentMesh->updateVertexAttributes(_callback) : 0; } diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h index 49e98e22d37..009d7b257cf 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h @@ -7,13 +7,10 @@ #pragma once -#include - #include "ScriptableMesh.h" #include class ScriptValue; -using ScriptValuePointer = QSharedPointer; namespace scriptable { /*@jsdoc @@ -288,7 +285,7 @@ namespace scriptable { * @param {GraphicsMesh~updateVertexAttributesCallback} callback - The function to call for each vertex. * @returns {number} The number of vertices the callback was called for. */ - glm::uint32 updateVertexAttributes(ScriptValuePointer callback); + glm::uint32 updateVertexAttributes(const ScriptValue& callback); /*@jsdoc * Calls a function for each vertex in the whole mesh (i.e., parent and mesh parts). @@ -296,7 +293,7 @@ namespace scriptable { * @param {GraphicsMesh~forEachVertexCallback} callback - The function to call for each vertex. * @returns {number} The number of vertices the callback was called for. */ - glm::uint32 forEachVertex(ScriptValuePointer callback); + glm::uint32 forEachVertex(const ScriptValue& callback); /*@jsdoc * Checks if an index is valid and, optionally, that vertex has a particular attribute. diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp index 2885a9a5de3..ed61fa049f5 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -262,7 +262,7 @@ scriptable::ScriptableMeshes scriptable::ScriptableModel::getMeshes() { } #if 0 -glm::uint32 scriptable::ScriptableModel::forEachVertexAttribute(ScriptValuePointer callback) { +glm::uint32 scriptable::ScriptableModel::forEachVertexAttribute(const ScriptValue& callback) { glm::uint32 result = 0; scriptable::ScriptableMeshes in = getMeshes(); if (in.size()) { diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt index b1fcc4076a0..bc48c10b3a7 100644 --- a/libraries/input-plugins/CMakeLists.txt +++ b/libraries/input-plugins/CMakeLists.txt @@ -1,5 +1,6 @@ set(TARGET_NAME input-plugins) setup_hifi_library() link_hifi_libraries(shared plugins ui-plugins controllers ui) +include_hifi_library_headers(script-engine) GroupSources("src/input-plugins") diff --git a/libraries/recording/src/recording/RecordingScriptingInterface.cpp b/libraries/recording/src/recording/RecordingScriptingInterface.cpp index f712a4c813c..82fefe26952 100644 --- a/libraries/recording/src/recording/RecordingScriptingInterface.cpp +++ b/libraries/recording/src/recording/RecordingScriptingInterface.cpp @@ -56,19 +56,19 @@ float RecordingScriptingInterface::playerLength() const { return _player->length(); } -void RecordingScriptingInterface::playClip(NetworkClipLoaderPointer clipLoader, const QString& url, ScriptValuePointer callback) { +void RecordingScriptingInterface::playClip(NetworkClipLoaderPointer clipLoader, const QString& url, const ScriptValue& callback) { _player->queueClip(clipLoader->getClip()); - if (callback->isFunction()) { - auto engine = callback->engine(); + if (callback.isFunction()) { + auto engine = callback.engine(); ScriptValueList args{ engine->newValue(true), engine->newValue(url) }; - callback->call(ScriptValuePointer(), args); + callback.call(ScriptValue(), args); } } -void RecordingScriptingInterface::loadRecording(const QString& url, ScriptValuePointer callback) { +void RecordingScriptingInterface::loadRecording(const QString& url, const ScriptValue& callback) { if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "loadRecording", Q_ARG(const QString&, url), Q_ARG(ScriptValuePointer, callback)); + BLOCKING_INVOKE_METHOD(this, "loadRecording", Q_ARG(const QString&, url), Q_ARG(const ScriptValue&, callback)); return; } @@ -85,7 +85,7 @@ void RecordingScriptingInterface::loadRecording(const QString& url, ScriptValueP auto weakClipLoader = clipLoader.toWeakRef(); - auto manager = callback->engine()->manager(); + auto manager = callback.engine()->manager(); if (!manager) { qWarning() << "This script does not belong to a ScriptManager"; return; @@ -110,10 +110,10 @@ void RecordingScriptingInterface::loadRecording(const QString& url, ScriptValueP [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable { qCDebug(scriptengine) << "Failed to load recording from\"" << url << '"'; - if (callback->isFunction()) { - auto engine = callback->engine(); + if (callback.isFunction()) { + auto engine = callback.engine(); ScriptValueList args{ engine->newValue(false), engine->newValue(url) }; - callback->call(ScriptValuePointer(), args); + callback.call(ScriptValue(), args); } if (auto clipLoader = weakClipLoader.toStrongRef()) { @@ -259,8 +259,8 @@ void RecordingScriptingInterface::saveRecording(const QString& filename) { recording::Clip::toFile(filename, _lastClip); } -bool RecordingScriptingInterface::saveRecordingToAsset(ScriptValuePointer getClipAtpUrl) { - if (!getClipAtpUrl->isFunction()) { +bool RecordingScriptingInterface::saveRecordingToAsset(const ScriptValue& getClipAtpUrl) { + if (!getClipAtpUrl.isFunction()) { qCWarning(scriptengine) << "The argument is not a function."; return false; } @@ -269,7 +269,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(ScriptValuePointer getCli bool result; BLOCKING_INVOKE_METHOD(this, "saveRecordingToAsset", Q_RETURN_ARG(bool, result), - Q_ARG(ScriptValuePointer, getClipAtpUrl)); + Q_ARG(const ScriptValue&, getClipAtpUrl)); return result; } @@ -278,7 +278,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(ScriptValuePointer getCli return false; } - auto manager = getClipAtpUrl->engine()->manager(); + auto manager = getClipAtpUrl.engine()->manager(); if (!manager) { qWarning() << "This script does not belong to a ScriptManager"; return false; @@ -297,8 +297,8 @@ bool RecordingScriptingInterface::saveRecordingToAsset(ScriptValuePointer getCli } ScriptValueList args; - args << getClipAtpUrl->engine()->newValue(clip_atp_url); - getClipAtpUrl->call(ScriptValuePointer(), args); + args << getClipAtpUrl.engine()->newValue(clip_atp_url); + getClipAtpUrl.call(ScriptValue(), args); }); upload->start(); return true; diff --git a/libraries/recording/src/recording/RecordingScriptingInterface.h b/libraries/recording/src/recording/RecordingScriptingInterface.h index f645e197007..126c81e3b43 100644 --- a/libraries/recording/src/recording/RecordingScriptingInterface.h +++ b/libraries/recording/src/recording/RecordingScriptingInterface.h @@ -19,13 +19,12 @@ #include #include +#include + #include "ClipCache.h" #include "Forward.h" #include "Frame.h" -class ScriptValue; -using ScriptValuePointer = QSharedPointer; - /*@jsdoc * The Recording API makes and plays back recordings of voice and avatar movements. Playback may be done on a * user's avatar or an assignment client agent (see the {@link Agent} API). @@ -72,7 +71,7 @@ public slots: * }); * } */ - void loadRecording(const QString& url, ScriptValuePointer callback = ScriptValuePointer()); + void loadRecording(const QString& url, const ScriptValue& callback = ScriptValue()); /*@jsdoc @@ -336,7 +335,7 @@ public slots: * } * }, 5000); */ - bool saveRecordingToAsset(ScriptValuePointer getClipAtpUrl); + bool saveRecordingToAsset(const ScriptValue& getClipAtpUrl); /*@jsdoc * Loads the most recently made recording and plays it back on your avatar. @@ -369,7 +368,7 @@ public slots: QSet _clipLoaders; private: - void playClip(recording::NetworkClipLoaderPointer clipLoader, const QString& url, ScriptValuePointer callback); + void playClip(recording::NetworkClipLoaderPointer clipLoader, const QString& url, const ScriptValue& callback); }; #endif // hifi_RecordingScriptingInterface_h diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index d9e193ee501..6ac1a3518e1 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -7,6 +7,7 @@ link_hifi_libraries(shared task ktx gpu shaders graphics graphics-scripting mate include_hifi_library_headers(audio) include_hifi_library_headers(networking) include_hifi_library_headers(octree) +include_hifi_library_headers(script-engine) include_hifi_library_headers(hfm) # tell CMake to exclude qrc_fonts.cpp for policy CMP0071 diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index 942df370f51..99ef12ab62c 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -63,7 +63,7 @@ bool AssetScriptingInterface::initializeCache() { } } -void AssetScriptingInterface::uploadData(QString data, ScriptValuePointer callback) { +void AssetScriptingInterface::uploadData(QString data, const ScriptValue& callback) { auto handler = jsBindCallback(thisObject(), callback); QByteArray dataByteArray = data.toUtf8(); auto upload = DependencyManager::get()->createUpload(dataByteArray); @@ -88,7 +88,7 @@ void AssetScriptingInterface::uploadData(QString data, ScriptValuePointer callba upload->start(); } -void AssetScriptingInterface::setMapping(QString path, QString hash, ScriptValuePointer callback) { +void AssetScriptingInterface::setMapping(QString path, QString hash, const ScriptValue& callback) { auto handler = jsBindCallback(thisObject(), callback); auto setMappingRequest = assetClient()->createSetMappingRequest(path, hash); Promise deferred = makePromise(__FUNCTION__); @@ -113,7 +113,7 @@ void AssetScriptingInterface::setMapping(QString path, QString hash, ScriptValue * @typedef {object} Assets.DownloadDataError * @property {string} errorMessage - "" if the download was successful, otherwise a description of the error. */ -void AssetScriptingInterface::downloadData(QString urlString, ScriptValuePointer callback) { +void AssetScriptingInterface::downloadData(QString urlString, const ScriptValue& callback) { // FIXME: historically this API method failed silently when given a non-atp prefixed // urlString (or if the AssetRequest failed). // .. is that by design or could we update without breaking things to provide better feedback to scripts? @@ -156,7 +156,7 @@ void AssetScriptingInterface::downloadData(QString urlString, ScriptValuePointer assetRequest->start(); } -void AssetScriptingInterface::setBakingEnabled(QString path, bool enabled, ScriptValuePointer callback) { +void AssetScriptingInterface::setBakingEnabled(QString path, bool enabled, const ScriptValue& callback) { auto setBakingEnabledRequest = DependencyManager::get()->createSetBakingEnabledRequest({ path }, enabled); Promise deferred = jsPromiseReady(makePromise(__FUNCTION__), thisObject(), callback); @@ -186,11 +186,11 @@ void AssetScriptingInterface::sendFakedHandshake() { #endif -void AssetScriptingInterface::getMapping(QString asset, ScriptValuePointer callback) { +void AssetScriptingInterface::getMapping(QString asset, const ScriptValue& callback) { auto path = AssetUtils::getATPUrl(asset).path(); auto handler = jsBindCallback(thisObject(), callback); JS_VERIFY(AssetUtils::isValidFilePath(path), "invalid ATP file path: " + asset + "(path:"+path+")"); - JS_VERIFY(callback->isFunction(), "expected second parameter to be a callback function"); + JS_VERIFY(callback.isFunction(), "expected second parameter to be a callback function"); Promise promise = getAssetInfo(path); auto scriptEngine = engine(); promise->ready([=](QString error, QVariantMap result) { @@ -210,19 +210,19 @@ bool AssetScriptingInterface::jsVerify(bool condition, const QString& error) { return false; } -ScriptValuePointer AssetScriptingInterface::jsBindCallback(ScriptValuePointer scope, ScriptValuePointer callback) { - ScriptValuePointer handler = ::makeScopedHandlerObject(scope, callback); - ScriptValuePointer value = handler->property("callback"); - if (!jsVerify(handler->isObject() && value->isFunction(), - QString("jsBindCallback -- .callback is not a function (%1)").arg(value->toVariant().typeName()))) { - return ScriptValuePointer(); +ScriptValue AssetScriptingInterface::jsBindCallback(const ScriptValue& scope, const ScriptValue& callback) { + ScriptValue handler = ::makeScopedHandlerObject(scope, callback); + ScriptValue value = handler.property("callback"); + if (!jsVerify(handler.isObject() && value.isFunction(), + QString("jsBindCallback -- .callback is not a function (%1)").arg(value.toVariant().typeName()))) { + return ScriptValue(); } return handler; } -Promise AssetScriptingInterface::jsPromiseReady(Promise promise, ScriptValuePointer scope, ScriptValuePointer callback) { +Promise AssetScriptingInterface::jsPromiseReady(Promise promise, const ScriptValue& scope, const ScriptValue& callback) { auto handler = jsBindCallback(scope, callback); - if (!jsVerify(handler->isValid(), "jsPromiseReady -- invalid callback handler")) { + if (!jsVerify(handler.isValid(), "jsPromiseReady -- invalid callback handler")) { return nullptr; } auto scriptEngine = engine(); @@ -231,25 +231,25 @@ Promise AssetScriptingInterface::jsPromiseReady(Promise promise, ScriptValuePoin }); } -void AssetScriptingInterface::jsCallback(const ScriptValuePointer& handler, - const ScriptValuePointer& error, const ScriptValuePointer& result) { +void AssetScriptingInterface::jsCallback(const ScriptValue& handler, + const ScriptValue& error, const ScriptValue& result) { Q_ASSERT(thread() == QThread::currentThread()); - auto errorValue = !error->toBool() ? engine()->nullValue() : error; - JS_VERIFY(handler->isObject() && handler->property("callback")->isFunction(), + auto errorValue = !error.toBool() ? engine()->nullValue() : error; + JS_VERIFY(handler.isObject() && handler.property("callback").isFunction(), QString("jsCallback -- .callback is not a function (%1)") - .arg(handler->property("callback")->toVariant().typeName())); + .arg(handler.property("callback").toVariant().typeName())); ::callScopedHandlerObject(handler, errorValue, result); } -void AssetScriptingInterface::jsCallback(const ScriptValuePointer& handler, - const ScriptValuePointer& error, const QVariantMap& result) { +void AssetScriptingInterface::jsCallback(const ScriptValue& handler, + const ScriptValue& error, const QVariantMap& result) { Q_ASSERT(thread() == QThread::currentThread()); - Q_ASSERT(handler->engine()); - auto engine = handler->engine(); + Q_ASSERT(handler.engine()); + auto engine = handler.engine(); jsCallback(handler, error, engine->toScriptValue(result)); } -void AssetScriptingInterface::deleteAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { +void AssetScriptingInterface::deleteAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { jsVerify(false, "TODO: deleteAsset API"); } @@ -279,14 +279,14 @@ void AssetScriptingInterface::deleteAsset(ScriptValuePointer options, ScriptValu * @property {boolean} [wasRedirected] - true if the downloaded data is the baked version of the asset, * false if it isn't baked. */ -void AssetScriptingInterface::getAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { - JS_VERIFY(options->isObject() || options->isString(), "expected request options Object or URL as first parameter"); - - auto decompress = options->property("decompress")->toBool() || options->property("compressed")->toBool(); - auto responseType = options->property("responseType")->toString().toLower(); - auto url = options->property("url")->toString(); - if (options->isString()) { - url = options->toString(); +void AssetScriptingInterface::getAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { + JS_VERIFY(options.isObject() || options.isString(), "expected request options Object or URL as first parameter"); + + auto decompress = options.property("decompress").toBool() || options.property("compressed").toBool(); + auto responseType = options.property("responseType").toString().toLower(); + auto url = options.property("url").toString(); + if (options.isString()) { + url = options.toString(); } if (responseType.isEmpty()) { responseType = "text"; @@ -345,10 +345,10 @@ void AssetScriptingInterface::getAsset(ScriptValuePointer options, ScriptValuePo * @property {boolean} [wasRedirected] - true if the resolved data is for the baked version of the asset, * false if it isn't. */ -void AssetScriptingInterface::resolveAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { +void AssetScriptingInterface::resolveAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { const QString& URL{ "url" }; - auto url = (options->isString() ? options : options->property(URL))->toString(); + auto url = (options.isString() ? options : options.property(URL)).toString(); auto asset = AssetUtils::getATPUrl(url).path(); JS_VERIFY(AssetUtils::isValidFilePath(asset) || AssetUtils::isValidHash(asset), @@ -372,10 +372,10 @@ void AssetScriptingInterface::resolveAsset(ScriptValuePointer options, ScriptVal * @property {string|object|ArrayBuffer} [response] - The decompressed data. * @property {Assets.ResponseType} [responseType] - The type of the decompressed data in response. */ -void AssetScriptingInterface::decompressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { - auto data = options->property("data"); +void AssetScriptingInterface::decompressData(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { + auto data = options.property("data"); QByteArray dataByteArray = scriptvalue_cast(data); - auto responseType = options->property("responseType")->toString().toLower(); + auto responseType = options.property("responseType").toString().toLower(); if (responseType.isEmpty()) { responseType = "text"; } @@ -413,10 +413,10 @@ namespace { * @property {string} [contentType] - The MIME type of the compressed data, i.e., "application/gzip". * @property {ArrayBuffer} [data] - The compressed data. */ -void AssetScriptingInterface::compressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { - auto data = options->property("data")->isValid() ? options->property("data") : options; - QByteArray dataByteArray = data->isString() ? data->toString().toUtf8() : scriptvalue_cast(data); - int level = options->property("level")->isNumber() ? options->property("level")->toInt32() : DEFAULT_GZIP_COMPRESSION_LEVEL; +void AssetScriptingInterface::compressData(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { + auto data = options.property("data").isValid() ? options.property("data") : options; + QByteArray dataByteArray = data.isString() ? data.toString().toUtf8() : scriptvalue_cast(data); + int level = options.property("level").isNumber() ? options.property("level").toInt32() : DEFAULT_GZIP_COMPRESSION_LEVEL; JS_VERIFY(level >= DEFAULT_GZIP_COMPRESSION_LEVEL || level <= MAX_GZIP_COMPRESSION_LEVEL, QString("invalid .level %1").arg(level)); jsPromiseReady(compressBytes(dataByteArray, level), scope, callback); } @@ -442,18 +442,18 @@ void AssetScriptingInterface::compressData(ScriptValuePointer options, ScriptVal * @property {string} [url] - The atp: URL of the content: using the path if specified, otherwise the hash. * @property {string} [path] - The uploaded content's mapped path, if specified. */ -void AssetScriptingInterface::putAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { - auto compress = options->property("compress")->toBool() || options->property("compressed")->toBool(); - auto data = options->isObject() ? options->property("data") : options; - auto rawPath = options->property("path")->toString(); +void AssetScriptingInterface::putAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { + auto compress = options.property("compress").toBool() || options.property("compressed").toBool(); + auto data = options.isObject() ? options.property("data") : options; + auto rawPath = options.property("path").toString(); auto path = AssetUtils::getATPUrl(rawPath).path(); - QByteArray dataByteArray = data->isString() ? data->toString().toUtf8() : scriptvalue_cast(data); + QByteArray dataByteArray = data.isString() ? data.toString().toUtf8() : scriptvalue_cast(data); JS_VERIFY(path.isEmpty() || AssetUtils::isValidFilePath(path), QString("expected valid ATP file path '%1' ('%2')").arg(rawPath).arg(path)); JS_VERIFY(dataByteArray.size() > 0, - QString("expected non-zero .data (got %1 / #%2 bytes)").arg(data->toVariant().typeName()).arg(dataByteArray.size())); + QString("expected non-zero .data (got %1 / #%2 bytes)").arg(data.toVariant().typeName()).arg(dataByteArray.size())); // [compressed] => uploaded to server => [mapped to path] Promise prepared = makePromise("putAsset::prepared"); @@ -498,8 +498,8 @@ void AssetScriptingInterface::putAsset(ScriptValuePointer options, ScriptValuePo * @property {string} url - The URL of the cached asset to get information on. Must start with "atp:" or * "cache:". */ -void AssetScriptingInterface::queryCacheMeta(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { - QString url = options->isString() ? options->toString() : options->property("url")->toString(); +void AssetScriptingInterface::queryCacheMeta(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { + QString url = options.isString() ? options.toString() : options.property("url").toString(); JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url)); jsPromiseReady(Parent::queryCacheMeta(url), scope, callback); } @@ -513,16 +513,16 @@ void AssetScriptingInterface::queryCacheMeta(ScriptValuePointer options, ScriptV * @property {string} url - The URL of the asset to load from cache. Must start with "atp:" or * "cache:". */ -void AssetScriptingInterface::loadFromCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { +void AssetScriptingInterface::loadFromCache(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { QString url, responseType; bool decompress = false; - if (options->isString()) { - url = options->toString(); + if (options.isString()) { + url = options.toString(); responseType = "text"; } else { - url = options->property("url")->toString(); - responseType = options->property("responseType")->isValid() ? options->property("responseType")->toString() : "text"; - decompress = options->property("decompress")->toBool() || options->property("compressed")->toBool(); + url = options.property("url").toString(); + responseType = options.property("responseType").isValid() ? options.property("responseType").toString() : "text"; + decompress = options.property("decompress").toBool() || options.property("compressed").toBool(); } JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url)); JS_VERIFY(RESPONSE_TYPES.contains(responseType), @@ -555,17 +555,21 @@ bool AssetScriptingInterface::canWriteCacheValue(const QUrl& url) { * @property {string} [url] - The URL to associate with the cache item. Must start with "atp:" or * "cache:". If not specified, the URL is "atp:" followed by the SHA256 hash of the content. */ -void AssetScriptingInterface::saveToCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) { - JS_VERIFY(options->isObject(), QString("expected options object as first parameter not: %1").arg(options->toVariant().typeName())); +void AssetScriptingInterface::saveToCache(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) { + JS_VERIFY(options.isObject(), QString("expected options object as first parameter not: %1").arg(options.toVariant().typeName())); - QString url = options->property("url")->toString(); - QByteArray data = scriptvalue_cast(options->property("data")); - QVariantMap headers = scriptvalue_cast(options->property("headers")); + QString url = options.property("url").toString(); + QByteArray data = scriptvalue_cast(options.property("data")); + QVariantMap headers = scriptvalue_cast(options.property("headers")); saveToCache(url, data, headers, scope, callback); } -void AssetScriptingInterface::saveToCache(const QUrl& rawURL, const QByteArray& data, const QVariantMap& metadata, ScriptValuePointer scope, ScriptValuePointer callback) { +void AssetScriptingInterface::saveToCache(const QUrl& rawURL, + const QByteArray& data, + const QVariantMap& metadata, + const ScriptValue& scope, + const ScriptValue& callback) { QUrl url = rawURL; if (url.path().isEmpty() && !data.isEmpty()) { // generate a valid ATP URL from the data -- appending any existing fragment or querystring values diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 2e07c45c383..afec316e9a2 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -23,12 +23,9 @@ #include #include #include -#include #include "Scriptable.h" - -class ScriptValue; -using ScriptValuePointer = QSharedPointer; +#include "ScriptValue.h" /*@jsdoc * The Assets API provides facilities for interacting with the domain's asset server and the client cache. @@ -79,7 +76,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * }); * }); */ - Q_INVOKABLE void uploadData(QString data, ScriptValuePointer callback); + Q_INVOKABLE void uploadData(QString data, const ScriptValue& callback); /*@jsdoc * Called when an {@link Assets.downloadData} call is complete. @@ -115,7 +112,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * }); * }, 1000); */ - Q_INVOKABLE void downloadData(QString url, ScriptValuePointer callback); + Q_INVOKABLE void downloadData(QString url, const ScriptValue& callback); /*@jsdoc * Called when an {@link Assets.setMapping} call is complete. @@ -129,7 +126,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * @param {string} hash - The hash in the asset server. * @param {Assets~setMappingCallback} callback - The function to call upon completion. */ - Q_INVOKABLE void setMapping(QString path, QString hash, ScriptValuePointer callback); + Q_INVOKABLE void setMapping(QString path, QString hash, const ScriptValue& callback); /*@jsdoc * Called when an {@link Assets.getMapping} call is complete. @@ -153,7 +150,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * }); * } */ - Q_INVOKABLE void getMapping(QString path, ScriptValuePointer callback); + Q_INVOKABLE void getMapping(QString path, const ScriptValue& callback); /*@jsdoc * Called when an {@link Assets.setBakingEnabled} call is complete. @@ -169,7 +166,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * @param {Assets~setBakingEnabledCallback} callback - The function to call upon completion. */ // Note: Second callback parameter not documented because it's always {}. - Q_INVOKABLE void setBakingEnabled(QString path, bool enabled, ScriptValuePointer callback); + Q_INVOKABLE void setBakingEnabled(QString path, bool enabled, const ScriptValue& callback); #if (PR_BUILD || DEV_BUILD) /** @@ -225,7 +222,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * } * ); */ - Q_INVOKABLE void getAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void getAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Called when an {@link Assets.putAsset} call is complete. @@ -262,7 +259,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * } * ); */ - Q_INVOKABLE void putAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void putAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Called when an {@link Assets.deleteAsset} call is complete. @@ -279,7 +276,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * @param {object} scope - The scope that the callback function is defined in. * @param {Assets~deleteAssetCallback} callback - The function to call upon completion. */ - Q_INVOKABLE void deleteAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void deleteAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Called when an {@link Assets.resolveAsset} call is complete. @@ -313,7 +310,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * } * ); */ - Q_INVOKABLE void resolveAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void resolveAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Called when an {@link Assets.decompressData} call is complete. @@ -334,7 +331,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

*/ - Q_INVOKABLE void decompressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void decompressData(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Called when an {@link Assets.compressData} call is complete. @@ -356,7 +353,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

*/ - Q_INVOKABLE void compressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void compressData(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Initializes the cache if it isn't already initialized. @@ -401,7 +398,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * print("- Status: " + JSON.stringify(status)); * }); */ - Q_INVOKABLE void getCacheStatus(ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()) { + Q_INVOKABLE void getCacheStatus(const ScriptValue& scope, const ScriptValue& callback = ScriptValue()) { jsPromiseReady(Parent::getCacheStatus(), scope, callback); } @@ -441,7 +438,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * } * ); */ - Q_INVOKABLE void queryCacheMeta(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void queryCacheMeta(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Called when an {@link Assets.loadFromCache} call is complete. @@ -481,7 +478,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * } * ); */ - Q_INVOKABLE void loadFromCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void loadFromCache(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Called when an {@link Assets.saveToCache} call is complete. @@ -520,7 +517,7 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * } * ); */ - Q_INVOKABLE void saveToCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void saveToCache(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Saves asset data to the cache directly, without downloading it from a URL. @@ -540,13 +537,13 @@ class AssetScriptingInterface : public BaseAssetScriptingInterface, Scriptable { * scopeOrCallback.

*/ Q_INVOKABLE void saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& metadata, - ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); protected: - ScriptValuePointer jsBindCallback(ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); - Promise jsPromiseReady(Promise promise, ScriptValuePointer scope, ScriptValuePointer callback = ScriptValuePointer()); + ScriptValue jsBindCallback(const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); + Promise jsPromiseReady(Promise promise, const ScriptValue& scope, const ScriptValue& callback = ScriptValue()); - void jsCallback(const ScriptValuePointer& handler, const ScriptValuePointer& error, const QVariantMap& result); - void jsCallback(const ScriptValuePointer& handler, const ScriptValuePointer& error, const ScriptValuePointer& result); + void jsCallback(const ScriptValue& handler, const ScriptValue& error, const QVariantMap& result); + void jsCallback(const ScriptValue& handler, const ScriptValue& error, const ScriptValue& result); bool jsVerify(bool condition, const QString& error); }; diff --git a/libraries/script-engine/src/ConsoleScriptingInterface.cpp b/libraries/script-engine/src/ConsoleScriptingInterface.cpp index b36bd547a14..e8a4de24ad1 100644 --- a/libraries/script-engine/src/ConsoleScriptingInterface.cpp +++ b/libraries/script-engine/src/ConsoleScriptingInterface.cpp @@ -30,14 +30,14 @@ const QString SPACE_SEPARATOR = " "; const QString STACK_TRACE_FORMAT = "\n[Stacktrace]%1%2"; QList ConsoleScriptingInterface::_groupDetails = QList(); -ScriptValuePointer ConsoleScriptingInterface::info(ScriptContext* context, ScriptEngine* engine) { +ScriptValue ConsoleScriptingInterface::info(ScriptContext* context, ScriptEngine* engine) { if (ScriptManager* scriptManager = engine->manager()) { scriptManager->scriptInfoMessage(appendArguments(context)); } return engine->nullValue(); } -ScriptValuePointer ConsoleScriptingInterface::log(ScriptContext* context, ScriptEngine* engine) { +ScriptValue ConsoleScriptingInterface::log(ScriptContext* context, ScriptEngine* engine) { QString message = appendArguments(context); if (_groupDetails.count() == 0) { if (ScriptManager* scriptManager = engine->manager()) { @@ -49,28 +49,28 @@ ScriptValuePointer ConsoleScriptingInterface::log(ScriptContext* context, Script return engine->nullValue(); } -ScriptValuePointer ConsoleScriptingInterface::debug(ScriptContext* context, ScriptEngine* engine) { +ScriptValue ConsoleScriptingInterface::debug(ScriptContext* context, ScriptEngine* engine) { if (ScriptManager* scriptManager = engine->manager()) { scriptManager->scriptPrintedMessage(appendArguments(context)); } return engine->nullValue(); } -ScriptValuePointer ConsoleScriptingInterface::warn(ScriptContext* context, ScriptEngine* engine) { +ScriptValue ConsoleScriptingInterface::warn(ScriptContext* context, ScriptEngine* engine) { if (ScriptManager* scriptManager = engine->manager()) { scriptManager->scriptWarningMessage(appendArguments(context)); } return engine->nullValue(); } -ScriptValuePointer ConsoleScriptingInterface::error(ScriptContext* context, ScriptEngine* engine) { +ScriptValue ConsoleScriptingInterface::error(ScriptContext* context, ScriptEngine* engine) { if (ScriptManager* scriptManager = engine->manager()) { scriptManager->scriptErrorMessage(appendArguments(context)); } return engine->nullValue(); } -ScriptValuePointer ConsoleScriptingInterface::exception(ScriptContext* context, ScriptEngine* engine) { +ScriptValue ConsoleScriptingInterface::exception(ScriptContext* context, ScriptEngine* engine) { if (ScriptManager* scriptManager = engine->manager()) { scriptManager->scriptErrorMessage(appendArguments(context)); } @@ -108,14 +108,14 @@ void ConsoleScriptingInterface::timeEnd(QString labelName) { } } -ScriptValuePointer ConsoleScriptingInterface::assertion(ScriptContext* context, ScriptEngine* engine) { +ScriptValue ConsoleScriptingInterface::assertion(ScriptContext* context, ScriptEngine* engine) { QString message; bool condition = false; for (int i = 0; i < context->argumentCount(); i++) { if (i == 0) { - condition = context->argument(i)->toBool(); // accept first value as condition + condition = context->argument(i).toBool(); // accept first value as condition } else { - message += SPACE_SEPARATOR + context->argument(i)->toString(); // accept other parameters as message + message += SPACE_SEPARATOR + context->argument(i).toString(); // accept other parameters as message } } @@ -148,19 +148,19 @@ void ConsoleScriptingInterface::clear() { } } -ScriptValuePointer ConsoleScriptingInterface::group(ScriptContext* context, ScriptEngine* engine) { - logGroupMessage(context->argument(0)->toString(), engine); // accept first parameter as label - _groupDetails.push_back(context->argument(0)->toString()); +ScriptValue ConsoleScriptingInterface::group(ScriptContext* context, ScriptEngine* engine) { + logGroupMessage(context->argument(0).toString(), engine); // accept first parameter as label + _groupDetails.push_back(context->argument(0).toString()); return engine->nullValue(); } -ScriptValuePointer ConsoleScriptingInterface::groupCollapsed(ScriptContext* context, ScriptEngine* engine) { - logGroupMessage(context->argument(0)->toString(), engine); // accept first parameter as label - _groupDetails.push_back(context->argument(0)->toString()); +ScriptValue ConsoleScriptingInterface::groupCollapsed(ScriptContext* context, ScriptEngine* engine) { + logGroupMessage(context->argument(0).toString(), engine); // accept first parameter as label + _groupDetails.push_back(context->argument(0).toString()); return engine->nullValue(); } -ScriptValuePointer ConsoleScriptingInterface::groupEnd(ScriptContext* context, ScriptEngine* engine) { +ScriptValue ConsoleScriptingInterface::groupEnd(ScriptContext* context, ScriptEngine* engine) { ConsoleScriptingInterface::_groupDetails.removeLast(); return engine->nullValue(); } @@ -171,7 +171,7 @@ QString ConsoleScriptingInterface::appendArguments(ScriptContext* context) { if (i > 0) { message += SPACE_SEPARATOR; } - message += context->argument(i)->toString(); + message += context->argument(i).toString(); } return message; } diff --git a/libraries/script-engine/src/ConsoleScriptingInterface.h b/libraries/script-engine/src/ConsoleScriptingInterface.h index f9fa94895ba..09a44259c5f 100644 --- a/libraries/script-engine/src/ConsoleScriptingInterface.h +++ b/libraries/script-engine/src/ConsoleScriptingInterface.h @@ -27,14 +27,12 @@ #include #include #include -#include #include "Scriptable.h" +#include "ScriptValue.h" class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * The console API provides program logging facilities. @@ -58,7 +56,7 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * @function console.info * @param {...*} [message] - The message values to log. */ - static ScriptValuePointer info(ScriptContext* context, ScriptEngine* engine); + static ScriptValue info(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Logs a message to the program log and triggers {@link Script.printedMessage}. @@ -76,7 +74,7 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * // string 7 true * // INFO - Console.log message: "string 7 true" in [console.js] */ - static ScriptValuePointer log(ScriptContext* context, ScriptEngine* engine); + static ScriptValue log(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Logs a message to the program log and triggers {@link Script.printedMessage}. @@ -84,7 +82,7 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * @function console.debug * @param {...*} [message] - The message values to log. */ - static ScriptValuePointer debug(ScriptContext* context, ScriptEngine* engine); + static ScriptValue debug(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Logs a "WARNING" message to the program log and triggers {@link Script.warningMessage}. @@ -92,7 +90,7 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * @function console.warn * @param {...*} [message] - The message values to log. */ - static ScriptValuePointer warn(ScriptContext* context, ScriptEngine* engine); + static ScriptValue warn(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Logs an "ERROR" message to the program log and triggers {@link Script.errorMessage}. @@ -100,7 +98,7 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * @function console.error * @param {...*} [message] - The message values to log. */ - static ScriptValuePointer error(ScriptContext* context, ScriptEngine* engine); + static ScriptValue error(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * A synonym of {@link console.error}. @@ -109,7 +107,7 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * @function console.exception * @param {...*} [message] - The message values to log. */ - static ScriptValuePointer exception(ScriptContext* context, ScriptEngine* engine); + static ScriptValue exception(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Logs an "ERROR" message to the program log and triggers {@link Script.errorMessage}, if a test condition fails. @@ -132,7 +130,7 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * // INFO - Script continues running. */ // Note: Is registered in the script engine as "assert" - static ScriptValuePointer assertion(ScriptContext* context, ScriptEngine* engine); + static ScriptValue assertion(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Logs a message to the program log and triggers {@link Script.printedMessage}, then starts indenting subsequent @@ -160,7 +158,7 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * // Sentence 5 * //Sentence 6 */ - static ScriptValuePointer group(ScriptContext* context, ScriptEngine* engine); + static ScriptValue group(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Has the same behavior as {@link console.group}. @@ -169,13 +167,13 @@ class ConsoleScriptingInterface : public QObject, protected Scriptable { * @function console.groupCollapsed * @param {*} message - The message value to log. */ - static ScriptValuePointer groupCollapsed(ScriptContext* context, ScriptEngine* engine); + static ScriptValue groupCollapsed(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * Finishes a group of indented {@link console.log} messages. * @function console.groupEnd */ - static ScriptValuePointer groupEnd(ScriptContext* context, ScriptEngine* engine); + static ScriptValue groupEnd(ScriptContext* context, ScriptEngine* engine); public slots: diff --git a/libraries/script-engine/src/KeyEvent.cpp b/libraries/script-engine/src/KeyEvent.cpp index 41fdf4332ac..a6769c41c16 100644 --- a/libraries/script-engine/src/KeyEvent.cpp +++ b/libraries/script-engine/src/KeyEvent.cpp @@ -174,37 +174,37 @@ KeyEvent::operator QKeySequence() const { * print(JSON.stringify(event)); * }); */ -ScriptValuePointer KeyEvent::toScriptValue(ScriptEngine* engine, const KeyEvent& event) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("key", event.key); - obj->setProperty("text", event.text); - obj->setProperty("isShifted", event.isShifted); - obj->setProperty("isMeta", event.isMeta); - obj->setProperty("isControl", event.isControl); - obj->setProperty("isAlt", event.isAlt); - obj->setProperty("isKeypad", event.isKeypad); - obj->setProperty("isAutoRepeat", event.isAutoRepeat); +ScriptValue KeyEvent::toScriptValue(ScriptEngine* engine, const KeyEvent& event) { + ScriptValue obj = engine->newObject(); + obj.setProperty("key", event.key); + obj.setProperty("text", event.text); + obj.setProperty("isShifted", event.isShifted); + obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); + obj.setProperty("isKeypad", event.isKeypad); + obj.setProperty("isAutoRepeat", event.isAutoRepeat); return obj; } -void KeyEvent::fromScriptValue(const ScriptValuePointer& object, KeyEvent& event) { +void KeyEvent::fromScriptValue(const ScriptValue& object, KeyEvent& event) { event.isValid = false; // assume the worst - event.isMeta = object->property("isMeta")->toVariant().toBool(); - event.isControl = object->property("isControl")->toVariant().toBool(); - event.isAlt = object->property("isAlt")->toVariant().toBool(); - event.isKeypad = object->property("isKeypad")->toVariant().toBool(); - event.isAutoRepeat = object->property("isAutoRepeat")->toVariant().toBool(); + event.isMeta = object.property("isMeta").toVariant().toBool(); + event.isControl = object.property("isControl").toVariant().toBool(); + event.isAlt = object.property("isAlt").toVariant().toBool(); + event.isKeypad = object.property("isKeypad").toVariant().toBool(); + event.isAutoRepeat = object.property("isAutoRepeat").toVariant().toBool(); - ScriptValuePointer key = object->property("key"); - if (key->isValid()) { - event.key = key->toVariant().toInt(); + ScriptValue key = object.property("key"); + if (key.isValid()) { + event.key = key.toVariant().toInt(); event.text = QString(QChar(event.key)); event.isValid = true; } else { - ScriptValuePointer text = object->property("text"); - if (text->isValid()) { - event.text = object->property("text")->toVariant().toString(); + ScriptValue text = object.property("text"); + if (text.isValid()) { + event.text = object.property("text").toVariant().toString(); // if the text is a special command, then map it here... // TODO: come up with more elegant solution here, a map? is there a Qt function that gives nice names for keys? @@ -283,9 +283,9 @@ void KeyEvent::fromScriptValue(const ScriptValuePointer& object, KeyEvent& event } } - ScriptValuePointer isShifted = object->property("isShifted"); - if (isShifted->isValid()) { - event.isShifted = isShifted->toVariant().toBool(); + ScriptValue isShifted = object.property("isShifted"); + if (isShifted.isValid()) { + event.isShifted = isShifted.toVariant().toBool(); } else { // if no isShifted was included, get it from the text QChar character = event.text.at(0); diff --git a/libraries/script-engine/src/KeyEvent.h b/libraries/script-engine/src/KeyEvent.h index eb503da0e14..a40ece47bbf 100644 --- a/libraries/script-engine/src/KeyEvent.h +++ b/libraries/script-engine/src/KeyEvent.h @@ -16,11 +16,10 @@ #define hifi_KeyEvent_h #include -#include + +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// Represents a keyboard event to the scripting engine. Exposed as KeyEvent class KeyEvent { @@ -30,8 +29,8 @@ class KeyEvent { bool operator==(const KeyEvent& other) const; operator QKeySequence() const; - static ScriptValuePointer toScriptValue(ScriptEngine* engine, const KeyEvent& event); - static void fromScriptValue(const ScriptValuePointer& object, KeyEvent& event); + static ScriptValue toScriptValue(ScriptEngine* engine, const KeyEvent& event); + static void fromScriptValue(const ScriptValue& object, KeyEvent& event); int key; QString text; diff --git a/libraries/script-engine/src/LocationScriptingInterface.cpp b/libraries/script-engine/src/LocationScriptingInterface.cpp index 466ac779dab..505af4bbefc 100644 --- a/libraries/script-engine/src/LocationScriptingInterface.cpp +++ b/libraries/script-engine/src/LocationScriptingInterface.cpp @@ -21,12 +21,12 @@ LocationScriptingInterface* LocationScriptingInterface::getInstance() { return &sharedInstance; } -ScriptValuePointer LocationScriptingInterface::locationGetter(ScriptContext* context, ScriptEngine* engine) { +ScriptValue LocationScriptingInterface::locationGetter(ScriptContext* context, ScriptEngine* engine) { return engine->newQObject(DependencyManager::get().data()); } -ScriptValuePointer LocationScriptingInterface::locationSetter(ScriptContext* context, ScriptEngine* engine) { - const QVariant& argumentVariant = context->argument(0)->toVariant(); +ScriptValue LocationScriptingInterface::locationSetter(ScriptContext* context, ScriptEngine* engine) { + const QVariant& argumentVariant = context->argument(0).toVariant(); // just try and convert the argument to a string, should be a hifi:// address QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", diff --git a/libraries/script-engine/src/LocationScriptingInterface.h b/libraries/script-engine/src/LocationScriptingInterface.h index 7603e113fa4..0f7f4ded18c 100644 --- a/libraries/script-engine/src/LocationScriptingInterface.h +++ b/libraries/script-engine/src/LocationScriptingInterface.h @@ -12,20 +12,18 @@ #ifndef hifi_LocationScriptingInterface_h #define hifi_LocationScriptingInterface_h -#include +#include "ScriptValue.h" class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class LocationScriptingInterface : public QObject { Q_OBJECT public: static LocationScriptingInterface* getInstance(); - static ScriptValuePointer locationGetter(ScriptContext* context, ScriptEngine* engine); - static ScriptValuePointer locationSetter(ScriptContext* context, ScriptEngine* engine); + static ScriptValue locationGetter(ScriptContext* context, ScriptEngine* engine); + static ScriptValue locationSetter(ScriptContext* context, ScriptEngine* engine); private: LocationScriptingInterface() {}; }; diff --git a/libraries/script-engine/src/MIDIEvent.cpp b/libraries/script-engine/src/MIDIEvent.cpp index fb782d07fb6..d25ddc7e63c 100644 --- a/libraries/script-engine/src/MIDIEvent.cpp +++ b/libraries/script-engine/src/MIDIEvent.cpp @@ -26,18 +26,18 @@ const QString MIDI_EVENT_TYPE_PROP_NAME = "type"; const QString MIDI_DATA_1_PROP_NAME = "data1"; const QString MIDI_DATA_2_PROP_NAME = "data2"; -ScriptValuePointer midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty(MIDI_DELTA_TIME_PROP_NAME, event.deltaTime); - obj->setProperty(MIDI_EVENT_TYPE_PROP_NAME, event.type); - obj->setProperty(MIDI_DATA_1_PROP_NAME, event.data1); - obj->setProperty(MIDI_DATA_2_PROP_NAME, event.data2); +ScriptValue midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event) { + ScriptValue obj = engine->newObject(); + obj.setProperty(MIDI_DELTA_TIME_PROP_NAME, event.deltaTime); + obj.setProperty(MIDI_EVENT_TYPE_PROP_NAME, event.type); + obj.setProperty(MIDI_DATA_1_PROP_NAME, event.data1); + obj.setProperty(MIDI_DATA_2_PROP_NAME, event.data2); return obj; } -void midiEventFromScriptValue(const ScriptValuePointer &object, MIDIEvent& event) { - event.deltaTime = object->property(MIDI_DELTA_TIME_PROP_NAME)->toVariant().toDouble(); - event.type = object->property(MIDI_EVENT_TYPE_PROP_NAME)->toVariant().toUInt(); - event.data1 = object->property(MIDI_DATA_1_PROP_NAME)->toVariant().toUInt(); - event.data2 = object->property(MIDI_DATA_2_PROP_NAME)->toVariant().toUInt(); +void midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event) { + event.deltaTime = object.property(MIDI_DELTA_TIME_PROP_NAME).toVariant().toDouble(); + event.type = object.property(MIDI_EVENT_TYPE_PROP_NAME).toVariant().toUInt(); + event.data1 = object.property(MIDI_DATA_1_PROP_NAME).toVariant().toUInt(); + event.data2 = object.property(MIDI_DATA_2_PROP_NAME).toVariant().toUInt(); } \ No newline at end of file diff --git a/libraries/script-engine/src/MIDIEvent.h b/libraries/script-engine/src/MIDIEvent.h index 0d8138d8f66..1b2007cf3b5 100644 --- a/libraries/script-engine/src/MIDIEvent.h +++ b/libraries/script-engine/src/MIDIEvent.h @@ -15,11 +15,9 @@ #ifndef hifi_MIDIEvent_h #define hifi_MIDIEvent_h -#include +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// Represents a MIDI protocol event to the scripting engine. class MIDIEvent { @@ -34,8 +32,8 @@ Q_DECLARE_METATYPE(MIDIEvent) void registerMIDIMetaTypes(ScriptEngine* engine); -ScriptValuePointer midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event); -void midiEventFromScriptValue(const ScriptValuePointer &object, MIDIEvent& event); +ScriptValue midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event); +void midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event); #endif // hifi_MIDIEvent_h diff --git a/libraries/script-engine/src/MenuItemProperties.cpp b/libraries/script-engine/src/MenuItemProperties.cpp index 34d68981ee2..9864d7dd7f8 100644 --- a/libraries/script-engine/src/MenuItemProperties.cpp +++ b/libraries/script-engine/src/MenuItemProperties.cpp @@ -47,8 +47,8 @@ void registerMenuItemProperties(ScriptEngine* engine) { scriptRegisterMetaType(engine, menuItemPropertiesToScriptValue, menuItemPropertiesFromScriptValue); } -ScriptValuePointer menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItemProperties& properties) { - ScriptValuePointer obj = engine->newObject(); +ScriptValue menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItemProperties& properties) { + ScriptValue obj = engine->newObject(); // not supported return obj; } @@ -73,32 +73,32 @@ ScriptValuePointer menuItemPropertiesToScriptValue(ScriptEngine* engine, const M * @property {string} [afterItem] - The name of the menu item to place this menu item after. * @property {string} [grouping] - The name of grouping to add this menu item to. */ -void menuItemPropertiesFromScriptValue(const ScriptValuePointer& object, MenuItemProperties& properties) { - properties.menuName = object->property("menuName")->toVariant().toString(); - properties.menuItemName = object->property("menuItemName")->toVariant().toString(); - properties.isCheckable = object->property("isCheckable")->toVariant().toBool(); - properties.isChecked = object->property("isChecked")->toVariant().toBool(); - properties.isSeparator = object->property("isSeparator")->toVariant().toBool(); +void menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& properties) { + properties.menuName = object.property("menuName").toVariant().toString(); + properties.menuItemName = object.property("menuItemName").toVariant().toString(); + properties.isCheckable = object.property("isCheckable").toVariant().toBool(); + properties.isChecked = object.property("isChecked").toVariant().toBool(); + properties.isSeparator = object.property("isSeparator").toVariant().toBool(); // handle the shortcut key options in order... - ScriptValuePointer shortcutKeyValue = object->property("shortcutKey"); - if (shortcutKeyValue->isValid()) { - properties.shortcutKey = shortcutKeyValue->toVariant().toString(); + ScriptValue shortcutKeyValue = object.property("shortcutKey"); + if (shortcutKeyValue.isValid()) { + properties.shortcutKey = shortcutKeyValue.toVariant().toString(); properties.shortcutKeySequence = properties.shortcutKey; } else { - ScriptValuePointer shortcutKeyEventValue = object->property("shortcutKeyEvent"); - if (shortcutKeyEventValue->isValid()) { + ScriptValue shortcutKeyEventValue = object.property("shortcutKeyEvent"); + if (shortcutKeyEventValue.isValid()) { KeyEvent::fromScriptValue(shortcutKeyEventValue, properties.shortcutKeyEvent); properties.shortcutKeySequence = properties.shortcutKeyEvent; } } - if (object->property("position")->isValid()) { - properties.position = object->property("position")->toVariant().toInt(); + if (object.property("position").isValid()) { + properties.position = object.property("position").toVariant().toInt(); } - properties.beforeItem = object->property("beforeItem")->toVariant().toString(); - properties.afterItem = object->property("afterItem")->toVariant().toString(); - properties.grouping = object->property("grouping")->toVariant().toString(); + properties.beforeItem = object.property("beforeItem").toVariant().toString(); + properties.afterItem = object.property("afterItem").toVariant().toString(); + properties.grouping = object.property("grouping").toVariant().toString(); } diff --git a/libraries/script-engine/src/MenuItemProperties.h b/libraries/script-engine/src/MenuItemProperties.h index bcd127eacb8..fe36e7ce752 100644 --- a/libraries/script-engine/src/MenuItemProperties.h +++ b/libraries/script-engine/src/MenuItemProperties.h @@ -17,11 +17,9 @@ #include "KeyEvent.h" -#include +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// Represents a menu item a script may declare and bind events to. Exposed as MenuItemProperties class MenuItemProperties { @@ -56,8 +54,8 @@ class MenuItemProperties { static const int UNSPECIFIED_POSITION = -1; }; Q_DECLARE_METATYPE(MenuItemProperties) -ScriptValuePointer menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItemProperties& props); -void menuItemPropertiesFromScriptValue(const ScriptValuePointer& object, MenuItemProperties& props); +ScriptValue menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItemProperties& props); +void menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& props); void registerMenuItemProperties(ScriptEngine* engine); diff --git a/libraries/script-engine/src/MouseEvent.cpp b/libraries/script-engine/src/MouseEvent.cpp index b6a3e17c428..c436cb6f354 100644 --- a/libraries/script-engine/src/MouseEvent.cpp +++ b/libraries/script-engine/src/MouseEvent.cpp @@ -86,22 +86,22 @@ MouseEvent::MouseEvent(const QMouseEvent& event) : * print(JSON.stringify(event)); * }); */ -ScriptValuePointer MouseEvent::toScriptValue(ScriptEngine* engine, const MouseEvent& event) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("x", event.x); - obj->setProperty("y", event.y); - obj->setProperty("button", event.button); - obj->setProperty("isLeftButton", event.isLeftButton); - obj->setProperty("isRightButton", event.isRightButton); - obj->setProperty("isMiddleButton", event.isMiddleButton); - obj->setProperty("isShifted", event.isShifted); - obj->setProperty("isMeta", event.isMeta); - obj->setProperty("isControl", event.isControl); - obj->setProperty("isAlt", event.isAlt); +ScriptValue MouseEvent::toScriptValue(ScriptEngine* engine, const MouseEvent& event) { + ScriptValue obj = engine->newObject(); + obj.setProperty("x", event.x); + obj.setProperty("y", event.y); + obj.setProperty("button", event.button); + obj.setProperty("isLeftButton", event.isLeftButton); + obj.setProperty("isRightButton", event.isRightButton); + obj.setProperty("isMiddleButton", event.isMiddleButton); + obj.setProperty("isShifted", event.isShifted); + obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); return obj; } -void MouseEvent::fromScriptValue(const ScriptValuePointer& object, MouseEvent& event) { +void MouseEvent::fromScriptValue(const ScriptValue& object, MouseEvent& event) { // nothing for now... } diff --git a/libraries/script-engine/src/MouseEvent.h b/libraries/script-engine/src/MouseEvent.h index 49ddbdc2b0a..0d6453aee52 100644 --- a/libraries/script-engine/src/MouseEvent.h +++ b/libraries/script-engine/src/MouseEvent.h @@ -16,11 +16,10 @@ #define hifi_MouseEvent_h #include -#include + +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// Represents a mouse event to the scripting engine. Exposed as MouseEvent class MouseEvent { @@ -28,10 +27,10 @@ class MouseEvent { MouseEvent(); MouseEvent(const QMouseEvent& event); - static ScriptValuePointer toScriptValue(ScriptEngine* engine, const MouseEvent& event); - static void fromScriptValue(const ScriptValuePointer& object, MouseEvent& event); + static ScriptValue toScriptValue(ScriptEngine* engine, const MouseEvent& event); + static void fromScriptValue(const ScriptValue& object, MouseEvent& event); - ScriptValuePointer toScriptValue(ScriptEngine* engine) const { return MouseEvent::toScriptValue(engine, *this); } + ScriptValue toScriptValue(ScriptEngine* engine) const { return MouseEvent::toScriptValue(engine, *this); } int x; int y; diff --git a/libraries/script-engine/src/PointerEvent.cpp b/libraries/script-engine/src/PointerEvent.cpp index 487ac295c37..87cb95fa95d 100644 --- a/libraries/script-engine/src/PointerEvent.cpp +++ b/libraries/script-engine/src/PointerEvent.cpp @@ -125,97 +125,97 @@ void PointerEvent::setButton(Button button) { * * @typedef {number} KeyboardModifiers */ -ScriptValuePointer PointerEvent::toScriptValue(ScriptEngine* engine, const PointerEvent& event) { - ScriptValuePointer obj = engine->newObject(); +ScriptValue PointerEvent::toScriptValue(ScriptEngine* engine, const PointerEvent& event) { + ScriptValue obj = engine->newObject(); switch (event._type) { case Press: - obj->setProperty("type", "Press"); + obj.setProperty("type", "Press"); break; case DoublePress: - obj->setProperty("type", "DoublePress"); + obj.setProperty("type", "DoublePress"); break; case Release: - obj->setProperty("type", "Release"); + obj.setProperty("type", "Release"); break; default: case Move: - obj->setProperty("type", "Move"); + obj.setProperty("type", "Move"); break; }; - obj->setProperty("id", event._id); + obj.setProperty("id", event._id); - ScriptValuePointer pos2D = engine->newObject(); - pos2D->setProperty("x", event._pos2D.x); - pos2D->setProperty("y", event._pos2D.y); - obj->setProperty("pos2D", pos2D); + ScriptValue pos2D = engine->newObject(); + pos2D.setProperty("x", event._pos2D.x); + pos2D.setProperty("y", event._pos2D.y); + obj.setProperty("pos2D", pos2D); - ScriptValuePointer pos3D = engine->newObject(); - pos3D->setProperty("x", event._pos3D.x); - pos3D->setProperty("y", event._pos3D.y); - pos3D->setProperty("z", event._pos3D.z); - obj->setProperty("pos3D", pos3D); + ScriptValue pos3D = engine->newObject(); + pos3D.setProperty("x", event._pos3D.x); + pos3D.setProperty("y", event._pos3D.y); + pos3D.setProperty("z", event._pos3D.z); + obj.setProperty("pos3D", pos3D); - ScriptValuePointer normal = engine->newObject(); - normal->setProperty("x", event._normal.x); - normal->setProperty("y", event._normal.y); - normal->setProperty("z", event._normal.z); - obj->setProperty("normal", normal); + ScriptValue normal = engine->newObject(); + normal.setProperty("x", event._normal.x); + normal.setProperty("y", event._normal.y); + normal.setProperty("z", event._normal.z); + obj.setProperty("normal", normal); - ScriptValuePointer direction = engine->newObject(); - direction->setProperty("x", event._direction.x); - direction->setProperty("y", event._direction.y); - direction->setProperty("z", event._direction.z); - obj->setProperty("direction", direction); + ScriptValue direction = engine->newObject(); + direction.setProperty("x", event._direction.x); + direction.setProperty("y", event._direction.y); + direction.setProperty("z", event._direction.z); + obj.setProperty("direction", direction); bool isPrimaryButton = false; bool isSecondaryButton = false; bool isTertiaryButton = false; switch (event._button) { case NoButtons: - obj->setProperty("button", "None"); + obj.setProperty("button", "None"); break; case PrimaryButton: - obj->setProperty("button", "Primary"); + obj.setProperty("button", "Primary"); isPrimaryButton = true; break; case SecondaryButton: - obj->setProperty("button", "Secondary"); + obj.setProperty("button", "Secondary"); isSecondaryButton = true; break; case TertiaryButton: - obj->setProperty("button", "Tertiary"); + obj.setProperty("button", "Tertiary"); isTertiaryButton = true; break; } if (isPrimaryButton) { - obj->setProperty("isPrimaryButton", isPrimaryButton); - obj->setProperty("isLeftButton", isPrimaryButton); + obj.setProperty("isPrimaryButton", isPrimaryButton); + obj.setProperty("isLeftButton", isPrimaryButton); } if (isSecondaryButton) { - obj->setProperty("isSecondaryButton", isSecondaryButton); - obj->setProperty("isRightButton", isSecondaryButton); + obj.setProperty("isSecondaryButton", isSecondaryButton); + obj.setProperty("isRightButton", isSecondaryButton); } if (isTertiaryButton) { - obj->setProperty("isTertiaryButton", isTertiaryButton); - obj->setProperty("isMiddleButton", isTertiaryButton); + obj.setProperty("isTertiaryButton", isTertiaryButton); + obj.setProperty("isMiddleButton", isTertiaryButton); } - obj->setProperty("isPrimaryHeld", areFlagsSet(event._buttons, PrimaryButton)); - obj->setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton)); - obj->setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton)); + obj.setProperty("isPrimaryHeld", areFlagsSet(event._buttons, PrimaryButton)); + obj.setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton)); + obj.setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton)); - obj->setProperty("keyboardModifiers", engine->newValue(event.getKeyboardModifiers())); + obj.setProperty("keyboardModifiers", engine->newValue(event.getKeyboardModifiers())); return obj; } -void PointerEvent::fromScriptValue(const ScriptValuePointer& object, PointerEvent& event) { - if (object->isObject()) { - ScriptValuePointer type = object->property("type"); - QString typeStr = type->isString() ? type->toString() : "Move"; +void PointerEvent::fromScriptValue(const ScriptValue& object, PointerEvent& event) { + if (object.isObject()) { + ScriptValue type = object.property("type"); + QString typeStr = type.isString() ? type.toString() : "Move"; if (typeStr == "Press") { event._type = Press; } else if (typeStr == "DoublePress") { @@ -226,16 +226,16 @@ void PointerEvent::fromScriptValue(const ScriptValuePointer& object, PointerEven event._type = Move; } - ScriptValuePointer id = object->property("id"); - event._id = id->isNumber() ? (uint32_t)id->toNumber() : 0; + ScriptValue id = object.property("id"); + event._id = id.isNumber() ? (uint32_t)id.toNumber() : 0; - vec2FromScriptValue(object->property("pos2D"), event._pos2D); - vec3FromScriptValue(object->property("pos3D"), event._pos3D); - vec3FromScriptValue(object->property("normal"), event._normal); - vec3FromScriptValue(object->property("direction"), event._direction); + vec2FromScriptValue(object.property("pos2D"), event._pos2D); + vec3FromScriptValue(object.property("pos3D"), event._pos3D); + vec3FromScriptValue(object.property("normal"), event._normal); + vec3FromScriptValue(object.property("direction"), event._direction); - ScriptValuePointer button = object->property("button"); - QString buttonStr = type->isString() ? button->toString() : "NoButtons"; + ScriptValue button = object.property("button"); + QString buttonStr = type.isString() ? button.toString() : "NoButtons"; if (buttonStr == "Primary") { event._button = PrimaryButton; @@ -247,9 +247,9 @@ void PointerEvent::fromScriptValue(const ScriptValuePointer& object, PointerEven event._button = NoButtons; } - bool primary = object->property("isPrimaryHeld")->toBool(); - bool secondary = object->property("isSecondaryHeld")->toBool(); - bool tertiary = object->property("isTertiaryHeld")->toBool(); + bool primary = object.property("isPrimaryHeld").toBool(); + bool secondary = object.property("isSecondaryHeld").toBool(); + bool tertiary = object.property("isTertiaryHeld").toBool(); event._buttons = 0; if (primary) { event._buttons |= PrimaryButton; @@ -261,7 +261,7 @@ void PointerEvent::fromScriptValue(const ScriptValuePointer& object, PointerEven event._buttons |= TertiaryButton; } - event._keyboardModifiers = (Qt::KeyboardModifiers)(object->property("keyboardModifiers")->toUInt32()); + event._keyboardModifiers = (Qt::KeyboardModifiers)(object.property("keyboardModifiers").toUInt32()); } } diff --git a/libraries/script-engine/src/PointerEvent.h b/libraries/script-engine/src/PointerEvent.h index 3fd83ce5108..fb4617ba6eb 100644 --- a/libraries/script-engine/src/PointerEvent.h +++ b/libraries/script-engine/src/PointerEvent.h @@ -19,11 +19,10 @@ #include #include -#include + +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// Represents a 2D or 3D pointer to the scripting engine. Exposed as PointerEvent class PointerEvent { @@ -52,10 +51,10 @@ class PointerEvent { const glm::vec3& normal, const glm::vec3& direction, Button button = NoButtons, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::NoModifier); - static ScriptValuePointer toScriptValue(ScriptEngine* engine, const PointerEvent& event); - static void fromScriptValue(const ScriptValuePointer& object, PointerEvent& event); + static ScriptValue toScriptValue(ScriptEngine* engine, const PointerEvent& event); + static void fromScriptValue(const ScriptValue& object, PointerEvent& event); - ScriptValuePointer toScriptValue(ScriptEngine* engine) const { return PointerEvent::toScriptValue(engine, *this); } + ScriptValue toScriptValue(ScriptEngine* engine) const { return PointerEvent::toScriptValue(engine, *this); } EventType getType() const { return _type; } uint32_t getID() const { return _id; } diff --git a/libraries/script-engine/src/ScriptContext.h b/libraries/script-engine/src/ScriptContext.h index bb1f70da632..733d0b88f1b 100644 --- a/libraries/script-engine/src/ScriptContext.h +++ b/libraries/script-engine/src/ScriptContext.h @@ -19,14 +19,14 @@ #include #include +#include "ScriptValue.h" + class ScriptContext; class ScriptEngine; class ScriptFunctionContext; -class ScriptValue; using ScriptContextPointer = QSharedPointer; using ScriptFunctionContextPointer = QSharedPointer; using ScriptEnginePointer = QSharedPointer; -using ScriptValuePointer = QSharedPointer; /// [ScriptInterface] Provides an engine-independent interface for QScriptContextInfo class ScriptFunctionContext { @@ -49,15 +49,15 @@ class ScriptFunctionContext { class ScriptContext { public: virtual int argumentCount() const = 0; - virtual ScriptValuePointer argument(int index) const = 0; + virtual ScriptValue argument(int index) const = 0; virtual QStringList backtrace() const = 0; - virtual ScriptValuePointer callee() const = 0; + virtual ScriptValue callee() const = 0; virtual ScriptEnginePointer engine() const = 0; virtual ScriptFunctionContextPointer functionContext() const = 0; virtual ScriptContextPointer parentContext() const = 0; - virtual ScriptValuePointer thisObject() const = 0; - virtual ScriptValuePointer throwError(const QString& text) = 0; - virtual ScriptValuePointer throwValue(const ScriptValuePointer& value) = 0; + virtual ScriptValue thisObject() const = 0; + virtual ScriptValue throwError(const QString& text) = 0; + virtual ScriptValue throwValue(const ScriptValue& value) = 0; }; #endif // hifi_ScriptContext_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 3a243da60f8..fa791709d47 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -20,36 +20,36 @@ ScriptEnginePointer newScriptEngine(ScriptManager* manager) { return QSharedPointer(new ScriptEngineQtScript(manager)); } -ScriptValuePointer makeScopedHandlerObject(ScriptValuePointer scopeOrCallback, ScriptValuePointer methodOrName) { - auto engine = scopeOrCallback->engine(); +ScriptValue makeScopedHandlerObject(const ScriptValue& scopeOrCallback, const ScriptValue& methodOrName) { + auto engine = scopeOrCallback.engine(); if (!engine) { return scopeOrCallback; } - ScriptValuePointer scope; - ScriptValuePointer callback = scopeOrCallback; - if (scopeOrCallback->isObject()) { - if (methodOrName->isString()) { + ScriptValue scope; + ScriptValue callback = scopeOrCallback; + if (scopeOrCallback.isObject()) { + if (methodOrName.isString()) { scope = scopeOrCallback; - callback = scope->property(methodOrName->toString()); - } else if (methodOrName->isFunction()) { + callback = scope.property(methodOrName.toString()); + } else if (methodOrName.isFunction()) { scope = scopeOrCallback; callback = methodOrName; - } else if (!methodOrName->isValid()) { + } else if (!methodOrName.isValid()) { // instantiate from an existing scoped handler object - if (scopeOrCallback->property("callback")->isFunction()) { - scope = scopeOrCallback->property("scope"); - callback = scopeOrCallback->property("callback"); + if (scopeOrCallback.property("callback").isFunction()) { + scope = scopeOrCallback.property("scope"); + callback = scopeOrCallback.property("callback"); } } } auto handler = engine->newObject(); - handler->setProperty("scope", scope); - handler->setProperty("callback", callback); + handler.setProperty("scope", scope); + handler.setProperty("callback", callback); return handler; } -ScriptValuePointer callScopedHandlerObject(ScriptValuePointer handler, ScriptValuePointer err, ScriptValuePointer result) { - return handler->property("callback")->call(handler->property("scope"), ScriptValueList({ err, result })); +ScriptValue callScopedHandlerObject(const ScriptValue& handler, const ScriptValue& err, const ScriptValue& result) { + return handler.property("callback").call(handler.property("scope"), ScriptValueList({ err, result })); } bool ScriptEngine::IS_THREADSAFE_INVOCATION(const QString& method) { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 34b1846d7e6..b1fb6d4cd5c 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -20,6 +20,8 @@ #include #include +#include "ScriptValue.h" + class QByteArray; class QLatin1String; class QString; @@ -29,19 +31,17 @@ class ScriptContext; class ScriptEngine; class ScriptManager; class ScriptProgram; -class ScriptValue; using ScriptEnginePointer = QSharedPointer; using ScriptProgramPointer = QSharedPointer; -using ScriptValuePointer = QSharedPointer; Q_DECLARE_METATYPE(ScriptEnginePointer); /// [ScriptInterface] Provides an engine-independent interface for QScriptEngine class ScriptEngine { public: - typedef ScriptValuePointer (*FunctionSignature)(ScriptContext*, ScriptEngine*); - typedef ScriptValuePointer (*MarshalFunction)(ScriptEngine*, const void*); - typedef void (*DemarshalFunction)(const ScriptValuePointer&, void*); + typedef ScriptValue (*FunctionSignature)(ScriptContext*, ScriptEngine*); + typedef ScriptValue (*MarshalFunction)(ScriptEngine*, const void*); + typedef void (*DemarshalFunction)(const ScriptValue&, void*); enum ValueOwnership { QtOwnership = 0, @@ -65,47 +65,47 @@ class ScriptEngine { public: virtual void abortEvaluation() = 0; virtual void clearExceptions() = 0; - virtual ScriptValuePointer cloneUncaughtException(const QString& detail = QString()) = 0; + virtual ScriptValue cloneUncaughtException(const QString& detail = QString()) = 0; virtual ScriptContext* currentContext() const = 0; - virtual ScriptValuePointer evaluate(const QString& program, const QString& fileName = QString()) = 0; - virtual ScriptValuePointer evaluate(const ScriptProgramPointer &program) = 0; - virtual ScriptValuePointer evaluateInClosure(const ScriptValuePointer& locals, const ScriptProgramPointer& program) = 0; - virtual ScriptValuePointer globalObject() const = 0; + virtual ScriptValue evaluate(const QString& program, const QString& fileName = QString()) = 0; + virtual ScriptValue evaluate(const ScriptProgramPointer &program) = 0; + virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) = 0; + virtual ScriptValue globalObject() const = 0; virtual bool hasUncaughtException() const = 0; virtual bool isEvaluating() const = 0; - virtual ScriptValuePointer lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1) = 0; - virtual ScriptValuePointer makeError(const ScriptValuePointer& other = ScriptValuePointer(), const QString& type = "Error") = 0; + virtual ScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1) = 0; + virtual ScriptValue makeError(const ScriptValue& other = ScriptValue(), const QString& type = "Error") = 0; virtual ScriptManager* manager() const = 0; virtual bool maybeEmitUncaughtException(const QString& debugHint = QString()) = 0; - virtual ScriptValuePointer newArray(uint length = 0) = 0; - virtual ScriptValuePointer newArrayBuffer(const QByteArray& message) = 0; - virtual ScriptValuePointer newFunction(FunctionSignature fun, int length = 0) = 0; - virtual ScriptValuePointer newObject() = 0; + virtual ScriptValue newArray(uint length = 0) = 0; + virtual ScriptValue newArrayBuffer(const QByteArray& message) = 0; + virtual ScriptValue newFunction(FunctionSignature fun, int length = 0) = 0; + virtual ScriptValue newObject() = 0; virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName) = 0; - virtual ScriptValuePointer newQObject(QObject *object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions &options = QObjectWrapOptions()) = 0; - virtual ScriptValuePointer newValue(bool value) = 0; - virtual ScriptValuePointer newValue(int value) = 0; - virtual ScriptValuePointer newValue(uint value) = 0; - virtual ScriptValuePointer newValue(double value) = 0; - virtual ScriptValuePointer newValue(const QString& value) = 0; - virtual ScriptValuePointer newValue(const QLatin1String& value) = 0; - virtual ScriptValuePointer newValue(const char* value) = 0; - virtual ScriptValuePointer newVariant(const QVariant& value) = 0; - virtual ScriptValuePointer nullValue() = 0; - virtual bool raiseException(const ScriptValuePointer& exception) = 0; + virtual ScriptValue newQObject(QObject *object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions &options = QObjectWrapOptions()) = 0; + virtual ScriptValue newValue(bool value) = 0; + virtual ScriptValue newValue(int value) = 0; + virtual ScriptValue newValue(uint value) = 0; + virtual ScriptValue newValue(double value) = 0; + virtual ScriptValue newValue(const QString& value) = 0; + virtual ScriptValue newValue(const QLatin1String& value) = 0; + virtual ScriptValue newValue(const char* value) = 0; + virtual ScriptValue newVariant(const QVariant& value) = 0; + virtual ScriptValue nullValue() = 0; + virtual bool raiseException(const ScriptValue& exception) = 0; virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) = 0; virtual void registerFunction(const QString& name, FunctionSignature fun, int numArguments = -1) = 0; virtual void registerFunction(const QString& parent, const QString& name, FunctionSignature fun, int numArguments = -1) = 0; virtual void registerGetterSetter(const QString& name, FunctionSignature getter, FunctionSignature setter, const QString& parent = QString("")) = 0; virtual void registerGlobalObject(const QString& name, QObject* object) = 0; - virtual void setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype) = 0; + virtual void setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) = 0; virtual void setObjectName(const QString& name) = 0; virtual bool setProperty(const char* name, const QVariant& value) = 0; virtual void setProcessEventsInterval(int interval) = 0; virtual QThread* thread() const = 0; virtual void setThread(QThread* thread) = 0; - virtual ScriptValuePointer undefinedValue() = 0; - virtual ScriptValuePointer uncaughtException() const = 0; + virtual ScriptValue undefinedValue() = 0; + virtual ScriptValue uncaughtException() const = 0; virtual QStringList uncaughtExceptionBacktrace() const = 0; virtual int uncaughtExceptionLineNumber() const = 0; virtual void updateMemoryCost(const qint64& deltaSize) = 0; @@ -116,19 +116,19 @@ class ScriptEngine { public: template - inline T fromScriptValue(const ScriptValuePointer& value) { + inline T fromScriptValue(const ScriptValue& value) { return scriptvalue_cast(value); } template - inline ScriptValuePointer toScriptValue(const T& value) { + inline ScriptValue toScriptValue(const T& value) { return scriptValueFromValue(this, value); } public: // not for public use, but I don't like how Qt strings this along with private friend functions - virtual ScriptValuePointer create(int type, const void* ptr) = 0; - virtual bool convert(const ScriptValuePointer& value, int type, void* ptr) = 0; - virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df, const ScriptValuePointer& prototype) = 0; + virtual ScriptValue create(int type, const void* ptr) = 0; + virtual bool convert(const ScriptValue& value, int type, void* ptr) = 0; + virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df, const ScriptValue& prototype) = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptEngine::QObjectWrapOptions); @@ -143,8 +143,8 @@ ScriptEnginePointer newScriptEngine(ScriptManager* manager = nullptr); // auto handler = makeScopedHandlerObject(scopeOrCallback, optionalMethodOrName); // And then invoke the scoped handler later per CPS conventions: // auto result = callScopedHandlerObject(handler, err, result); -ScriptValuePointer makeScopedHandlerObject(ScriptValuePointer scopeOrCallback, ScriptValuePointer methodOrName); -ScriptValuePointer callScopedHandlerObject(ScriptValuePointer handler, ScriptValuePointer err, ScriptValuePointer result); +ScriptValue makeScopedHandlerObject(const ScriptValue& scopeOrCallback, const ScriptValue& methodOrName); +ScriptValue callScopedHandlerObject(const ScriptValue& handler, const ScriptValue& err, const ScriptValue& result); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Inline implementations diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h index d597efc7806..b378302fe2b 100644 --- a/libraries/script-engine/src/ScriptEngineCast.h +++ b/libraries/script-engine/src/ScriptEngineCast.h @@ -23,48 +23,48 @@ #include "ScriptValue.h" template -inline ScriptValuePointer scriptValueFromValue(ScriptEngine* engine, const T& t) { +inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const T& t) { if (!engine) { - return ScriptValuePointer(); + return ScriptValue(); } return engine->create(qMetaTypeId(), &t); } template <> -inline ScriptValuePointer scriptValueFromValue(ScriptEngine* engine, const QVariant& v) { +inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const QVariant& v) { if (!engine) { - return ScriptValuePointer(); + return ScriptValue(); } return engine->create(v.userType(), v.data()); } template -T scriptvalue_cast(const ScriptValuePointer& value) { +T scriptvalue_cast(const ScriptValue& value) { T t; const int id = qMetaTypeId(); - auto engine = value->engine(); + auto engine = value.engine(); if (engine && engine->convert(value, id, &t)) { return t; - } else if (value->isVariant()) { - return qvariant_cast(value->toVariant()); + } else if (value.isVariant()) { + return qvariant_cast(value.toVariant()); } return T(); } template <> -inline QVariant scriptvalue_cast(const ScriptValuePointer& value) { - return value->toVariant(); +inline QVariant scriptvalue_cast(const ScriptValue& value) { + return value.toVariant(); } template int scriptRegisterMetaType(ScriptEngine* eng, - ScriptValuePointer (*toScriptValue)(ScriptEngine*, const T& t), - void (*fromScriptValue)(const ScriptValuePointer&, T& t), - const ScriptValuePointer& prototype = ScriptValuePointer(), + ScriptValue (*toScriptValue)(ScriptEngine*, const T& t), + void (*fromScriptValue)(const ScriptValue&, T& t), + const ScriptValue& prototype = ScriptValue(), T* = 0) { const int id = qRegisterMetaType(); // make sure it's registered @@ -74,30 +74,30 @@ int scriptRegisterMetaType(ScriptEngine* eng, } template -ScriptValuePointer scriptValueFromSequence(ScriptEngine* eng, const Container& cont) { - ScriptValuePointer a = eng->newArray(); +ScriptValue scriptValueFromSequence(ScriptEngine* eng, const Container& cont) { + ScriptValue a = eng->newArray(); typename Container::const_iterator begin = cont.begin(); typename Container::const_iterator end = cont.end(); typename Container::const_iterator it; quint32 i; for (it = begin, i = 0; it != end; ++it, ++i) { - a->setProperty(i, eng->toScriptValue(*it)); + a.setProperty(i, eng->toScriptValue(*it)); } return a; } template -void scriptValueToSequence(const ScriptValuePointer& value, Container& cont) { - quint32 len = value->property(QLatin1String("length"))->toUInt32(); +void scriptValueToSequence(const ScriptValue& value, Container& cont) { + quint32 len = value.property(QLatin1String("length")).toUInt32(); for (quint32 i = 0; i < len; ++i) { - ScriptValuePointer item = value->property(i); + ScriptValue item = value.property(i); cont.push_back(scriptvalue_cast(item)); } } template int scriptRegisterSequenceMetaType(ScriptEngine* engine, - const ScriptValuePointer& prototype = ScriptValuePointer(), + const ScriptValue& prototype = ScriptValue(), T* = 0) { return scriptRegisterMetaType(engine, scriptValueFromSequence, scriptValueToSequence, prototype); } diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 06735094780..8f3ab7b4058 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -87,7 +87,7 @@ int scriptManagerPointerMetaID = qRegisterMetaType(); Q_DECLARE_METATYPE(ExternalResource::Bucket); -Q_DECLARE_METATYPE(ScriptValuePointer); +Q_DECLARE_METATYPE(ScriptValue); // --- Static script initialization registry @@ -109,21 +109,21 @@ static void runStaticInitializers(ScriptManager* manager) { // --- -static ScriptValuePointer debugPrint(ScriptContext* context, ScriptEngine* engine) { +static ScriptValue debugPrint(ScriptContext* context, ScriptEngine* engine) { // assemble the message by concatenating our arguments QString message = ""; for (int i = 0; i < context->argumentCount(); i++) { if (i > 0) { message += " "; } - message += context->argument(i)->toString(); + message += context->argument(i).toString(); } // was this generated by a script engine? If we don't recognize it then send the message and exit ScriptManager* scriptManager = engine->manager(); if (!scriptManager) { qCDebug(scriptengine_script, "%s", qUtf8Printable(message)); - return ScriptValuePointer(); + return ScriptValue(); } // This message was sent by one of our script engines, let's try to see if we can find the source. @@ -170,7 +170,7 @@ static ScriptValuePointer debugPrint(ScriptContext* context, ScriptEngine* engin qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(scriptManager->getFilename()), qUtf8Printable(message)); } - return ScriptValuePointer(); + return ScriptValue(); } // FIXME Come up with a way to properly encode entity IDs in filename @@ -193,7 +193,7 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID) return url + " [EntityID:" + entityID + "]"; } -QString ScriptManager::logException(const ScriptValuePointer& exception) { +QString ScriptManager::logException(const ScriptValue& exception) { auto message = formatException(exception, _enableExtendedJSExceptions.get()); scriptErrorMessage(message); return message; @@ -249,10 +249,10 @@ ScriptManager::ScriptManager(Context context, const QString& scriptContents, con } // this is where all unhandled exceptions end up getting logged - connect(this, &ScriptManager::unhandledException, this, [this](const ScriptValuePointer& err) { - auto output = err->engine() == _engine ? err : _engine->makeError(err); - if (!output->property("detail")->isValid()) { - output->setProperty("detail", "UnhandledException"); + connect(this, &ScriptManager::unhandledException, this, [this](const ScriptValue& err) { + auto output = err.engine() == _engine ? err : _engine->makeError(err); + if (!output.property("detail").isValid()) { + output.setProperty("detail", "UnhandledException"); } logException(output); }); @@ -516,10 +516,10 @@ void ScriptManager::clearDebugLogWindow() { // Templated qScriptRegisterMetaType fails to compile with raw pointers using ScriptableResourceRawPtr = ScriptableResource*; -static ScriptValuePointer scriptableResourceToScriptValue(ScriptEngine* engine, +static ScriptValue scriptableResourceToScriptValue(ScriptEngine* engine, const ScriptableResourceRawPtr& resource) { if (!resource) { - return ScriptValuePointer(); // probably shutting down + return ScriptValue(); // probably shutting down } // The first script to encounter this resource will track its memory. @@ -538,8 +538,8 @@ static ScriptValuePointer scriptableResourceToScriptValue(ScriptEngine* engine, return object; } -static void scriptableResourceFromScriptValue(const ScriptValuePointer& value, ScriptableResourceRawPtr& resource) { - resource = static_cast(value->toQObject()); +static void scriptableResourceFromScriptValue(const ScriptValue& value, ScriptableResourceRawPtr& resource) { + resource = static_cast(value.toQObject()); } /*@jsdoc @@ -555,7 +555,7 @@ static void scriptableResourceFromScriptValue(const ScriptValuePointer& value, S * * @property {Resource.State} State - The possible loading states of a resource. Read-only. */ -static ScriptValuePointer createScriptableResourcePrototype(ScriptManagerPointer manager) { +static ScriptValue createScriptableResourcePrototype(ScriptManagerPointer manager) { auto engine = manager->engine(); auto prototype = engine->newObject(); @@ -569,17 +569,17 @@ static ScriptValuePointer createScriptableResourcePrototype(ScriptManagerPointer auto prototypeState = engine->newQObject(state, ScriptEngine::QtOwnership, ScriptEngine::ExcludeSlots | ScriptEngine::ExcludeSuperClassMethods); - prototype->setProperty("State", prototypeState); + prototype.setProperty("State", prototypeState); return prototype; } -ScriptValuePointer externalResourceBucketToScriptValue(ScriptEngine* engine, ExternalResource::Bucket const& in) { +ScriptValue externalResourceBucketToScriptValue(ScriptEngine* engine, ExternalResource::Bucket const& in) { return engine->newValue((int)in); } -void externalResourceBucketFromScriptValue(const ScriptValuePointer& object, ExternalResource::Bucket& out) { - out = static_cast(object->toInt32()); +void externalResourceBucketFromScriptValue(const ScriptValue& object, ExternalResource::Bucket& out) { + out = static_cast(object.toInt32()); } void ScriptManager::resetModuleCache(bool deleteScriptCache) { @@ -587,33 +587,33 @@ void ScriptManager::resetModuleCache(bool deleteScriptCache) { executeOnScriptThread([=]() { resetModuleCache(deleteScriptCache); }); return; } - auto jsRequire = _engine->globalObject()->property("Script")->property("require"); - auto cache = jsRequire->property("cache"); - auto cacheMeta = jsRequire->data(); + auto jsRequire = _engine->globalObject().property("Script").property("require"); + auto cache = jsRequire.property("cache"); + auto cacheMeta = jsRequire.data(); if (deleteScriptCache) { - auto it = cache->newIterator(); + auto it = cache.newIterator(); while (it->hasNext()) { it->next(); if (it->flags() & ScriptValue::SkipInEnumeration) { continue; } qCDebug(scriptengine) << "resetModuleCache(true) -- staging " << it->name() << " for cache reset at next require"; - cacheMeta->setProperty(it->name(), true); + cacheMeta.setProperty(it->name(), true); } } cache = _engine->newObject(); - if (!cacheMeta->isObject()) { + if (!cacheMeta.isObject()) { cacheMeta = _engine->newObject(); - cacheMeta->setProperty("id", "Script.require.cacheMeta"); - cacheMeta->setProperty("type", "cacheMeta"); - jsRequire->setData(cacheMeta); + cacheMeta.setProperty("id", "Script.require.cacheMeta"); + cacheMeta.setProperty("type", "cacheMeta"); + jsRequire.setData(cacheMeta); } - cache->setProperty("__created__", (double)QDateTime::currentMSecsSinceEpoch(), ScriptValue::SkipInEnumeration); + cache.setProperty("__created__", (double)QDateTime::currentMSecsSinceEpoch(), ScriptValue::SkipInEnumeration); #if DEBUG_JS_MODULES cache.setProperty("__meta__", cacheMeta, READONLY_HIDDEN_PROP_FLAGS); #endif - jsRequire->setProperty("cache", cache, READONLY_PROP_FLAGS); + jsRequire.setProperty("cache", cache, READONLY_PROP_FLAGS); } void ScriptManager::init() { @@ -638,11 +638,11 @@ void ScriptManager::init() { scriptRegisterSequenceMetaType>(scriptEngine); scriptRegisterSequenceMetaType>(scriptEngine); - ScriptValuePointer xmlHttpRequestConstructorValue = scriptEngine->newFunction(XMLHttpRequestClass::constructor); - scriptEngine->globalObject()->setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); + ScriptValue xmlHttpRequestConstructorValue = scriptEngine->newFunction(XMLHttpRequestClass::constructor); + scriptEngine->globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); - ScriptValuePointer webSocketConstructorValue = scriptEngine->newFunction(WebSocketClass::constructor); - scriptEngine->globalObject()->setProperty("WebSocket", webSocketConstructorValue); + ScriptValue webSocketConstructorValue = scriptEngine->newFunction(WebSocketClass::constructor); + scriptEngine->globalObject().setProperty("WebSocket", webSocketConstructorValue); /*@jsdoc * Prints a message to the program log and emits {@link Script.printedMessage}. @@ -651,7 +651,7 @@ void ScriptManager::init() { * @function print * @param {...*} [message] - The message values to print. */ - scriptEngine->globalObject()->setProperty("print", scriptEngine->newFunction(debugPrint)); + scriptEngine->globalObject().setProperty("print", scriptEngine->newFunction(debugPrint)); scriptRegisterMetaType(scriptEngine, animationDetailsToScriptValue, animationDetailsFromScriptValue); scriptRegisterMetaType(scriptEngine, webSocketToScriptValue, webSocketFromScriptValue); @@ -665,10 +665,10 @@ void ScriptManager::init() { { // set up Script.require.resolve and Script.require.cache - auto Script = scriptEngine->globalObject()->property("Script"); - auto require = Script->property("require"); - auto resolve = Script->property("_requireResolve"); - require->setProperty("resolve", resolve, READONLY_PROP_FLAGS); + auto Script = scriptEngine->globalObject().property("Script"); + auto require = Script.property("require"); + auto resolve = Script.property("_requireResolve"); + require.setProperty("resolve", resolve, READONLY_PROP_FLAGS); resetModuleCache(); } @@ -697,12 +697,12 @@ void ScriptManager::init() { // Scriptable cache access auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast(sharedFromThis())); - scriptEngine->globalObject()->setProperty("Resource", resourcePrototype); + scriptEngine->globalObject().setProperty("Resource", resourcePrototype); scriptEngine->setDefaultPrototype(qMetaTypeId(), resourcePrototype); scriptRegisterMetaType(scriptEngine, scriptableResourceToScriptValue, scriptableResourceFromScriptValue); // constants - scriptEngine->globalObject()->setProperty("TREE_SCALE", scriptEngine->newValue(TREE_SCALE)); + scriptEngine->globalObject().setProperty("TREE_SCALE", scriptEngine->newValue(TREE_SCALE)); scriptEngine->registerGlobalObject("Assets", _assetScriptingInterface); scriptEngine->registerGlobalObject("Resources", DependencyManager::get().data()); @@ -718,14 +718,14 @@ void ScriptManager::init() { scriptEngine->registerGlobalObject("StackTest", new StackTestScriptingInterface(this)); #endif - scriptEngine->globalObject()->setProperty("KALILA", "isWaifu"); - scriptEngine->globalObject()->setProperty("Kute", scriptEngine->newFunction([](ScriptContext* context, ScriptEngine* engine) -> ScriptValuePointer { - return context->engine()->newValue(context->argument(0)->toString().toLower() == "kalila" ? true : false); + scriptEngine->globalObject().setProperty("KALILA", "isWaifu"); + scriptEngine->globalObject().setProperty("Kute", scriptEngine->newFunction([](ScriptContext* context, ScriptEngine* engine) -> ScriptValue { + return context->engine()->newValue(context->argument(0).toString().toLower() == "kalila" ? true : false); })); } // Unregister the handlers for this eventName and entityID. -void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler) { +void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QString& eventName, const ScriptValue& handler) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptManager::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " @@ -734,7 +734,7 @@ void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QStri QMetaObject::invokeMethod(this, "removeEventHandler", Q_ARG(const EntityItemID&, entityID), Q_ARG(const QString&, eventName), - Q_ARG(ScriptValuePointer, handler)); + Q_ARG(const ScriptValue&, handler)); return; } #ifdef THREAD_DEBUGGING @@ -746,9 +746,9 @@ void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QStri } RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID]; CallbackList& handlersForEvent = handlersOnEntity[eventName]; - // ScriptValuePointer does not have operator==(), so we can't use QList::removeOne and friends. So iterate. + // ScriptValue does not have operator==(), so we can't use QList::removeOne and friends. So iterate. for (int i = 0; i < handlersForEvent.count(); ++i) { - if (handlersForEvent[i].function->equals(handler)) { + if (handlersForEvent[i].function.equals(handler)) { handlersForEvent.removeAt(i); return; // Design choice: since comparison is relatively expensive, just remove the first matching handler. } @@ -771,7 +771,7 @@ void ScriptManager::removeAllEventHandlers(const EntityItemID& entityID) { } // Register the handler. -void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler) { +void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& eventName, const ScriptValue& handler) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptManager::addEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " @@ -781,7 +781,7 @@ void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& QMetaObject::invokeMethod(this, "addEventHandler", Q_ARG(const EntityItemID&, entityID), Q_ARG(const QString&, eventName), - Q_ARG(ScriptValuePointer, handler)); + Q_ARG(const ScriptValue&, handler)); return; } #ifdef THREAD_DEBUGGING @@ -951,7 +951,7 @@ void ScriptManager::run() { // only clear exceptions if we are not in the middle of evaluating if (!_engine->isEvaluating() && _engine->hasUncaughtException()) { qCWarning(scriptengine) << __FUNCTION__ << "---------- UNCAUGHT EXCEPTION --------"; - qCWarning(scriptengine) << "runInThread" << _engine->uncaughtException()->toString(); + qCWarning(scriptengine) << "runInThread" << _engine->uncaughtException().toString(); emit unhandledException(_engine->cloneUncaughtException(__FUNCTION__)); _engine->clearExceptions(); } @@ -1037,7 +1037,7 @@ void ScriptManager::timerFired() { } // call the associated JS function, if it exists - if (timerData.function->isValid()) { + if (timerData.function.isValid()) { PROFILE_RANGE(script, __FUNCTION__); auto preTimer = p_high_resolution_clock::now(); callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, ScriptValueList()); @@ -1045,11 +1045,11 @@ void ScriptManager::timerFired() { auto elapsed = (postTimer - preTimer); _totalTimerExecution += std::chrono::duration_cast(elapsed); } else { - qCWarning(scriptengine) << "timerFired -- invalid function" << timerData.function->toVariant().toString(); + qCWarning(scriptengine) << "timerFired -- invalid function" << timerData.function.toVariant().toString(); } } -QObject* ScriptManager::setupTimerWithInterval(const ScriptValuePointer& function, int intervalMS, bool isSingleShot) { +QObject* ScriptManager::setupTimerWithInterval(const ScriptValue& function, int intervalMS, bool isSingleShot) { // create the timer, add it to the map, and start it QTimer* newTimer = new QTimer(this); newTimer->setSingleShot(isSingleShot); @@ -1073,7 +1073,7 @@ QObject* ScriptManager::setupTimerWithInterval(const ScriptValuePointer& functio return newTimer; } -QObject* ScriptManager::setInterval(const ScriptValuePointer& function, int intervalMS) { +QObject* ScriptManager::setInterval(const ScriptValue& function, int intervalMS) { if (isStopped()) { scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename()); return NULL; // bail early @@ -1082,7 +1082,7 @@ QObject* ScriptManager::setInterval(const ScriptValuePointer& function, int inte return setupTimerWithInterval(function, intervalMS, false); } -QObject* ScriptManager::setTimeout(const ScriptValuePointer& function, int timeoutMS) { +QObject* ScriptManager::setTimeout(const ScriptValue& function, int timeoutMS) { if (isStopped()) { scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename()); return NULL; // bail early @@ -1174,7 +1174,7 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r } auto message = QString("Cannot find module '%1' (%2)").arg(displayId); - auto throwResolveError = [&](const ScriptValuePointer& error) -> QString { + auto throwResolveError = [&](const ScriptValue& error) -> QString { _engine->raiseException(error); _engine->maybeEmitUncaughtException("require.resolve"); return QString(); @@ -1253,73 +1253,73 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r } // retrieves the current parent module from the JS scope chain -ScriptValuePointer ScriptManager::currentModule() { +ScriptValue ScriptManager::currentModule() { if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return _engine->nullValue(); } - auto jsRequire = _engine->globalObject()->property("Script")->property("require"); - auto cache = jsRequire->property("cache"); - ScriptValuePointer candidate; + auto jsRequire = _engine->globalObject().property("Script").property("require"); + auto cache = jsRequire.property("cache"); + ScriptValue candidate; ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan - for (auto context = _engine->currentContext(); context && (!candidate || !candidate->isObject()); parentContext = context->parentContext(), context = parentContext.data()) { + for (auto context = _engine->currentContext(); context && !candidate.isObject(); parentContext = context->parentContext(), context = parentContext.data()) { auto contextInfo = context->functionContext(); - candidate = cache->property(contextInfo->fileName()); + candidate = cache.property(contextInfo->fileName()); } - if (!candidate || !candidate->isObject()) { - return ScriptValuePointer(); + if (!candidate.isObject()) { + return ScriptValue(); } return candidate; } // replaces or adds "module" to "parent.children[]" array // (for consistency with Node.js and userscript cache invalidation without "cache busters") -bool ScriptManager::registerModuleWithParent(const ScriptValuePointer& module, const ScriptValuePointer& parent) { - auto children = parent->property("children"); - if (children->isArray()) { - auto key = module->property("id"); - auto length = children->property("length")->toInt32(); +bool ScriptManager::registerModuleWithParent(const ScriptValue& module, const ScriptValue& parent) { + auto children = parent.property("children"); + if (children.isArray()) { + auto key = module.property("id"); + auto length = children.property("length").toInt32(); for (int i = 0; i < length; i++) { - if (children->property(i)->property("id")->strictlyEquals(key)) { - qCDebug(scriptengine_module) << key->toString() << " updating parent.children[" << i << "] = module"; - children->setProperty(i, module); + if (children.property(i).property("id").strictlyEquals(key)) { + qCDebug(scriptengine_module) << key.toString() << " updating parent.children[" << i << "] = module"; + children.setProperty(i, module); return true; } } - qCDebug(scriptengine_module) << key->toString() << " appending parent.children[" << length << "] = module"; - children->setProperty(length, module); + qCDebug(scriptengine_module) << key.toString() << " appending parent.children[" << length << "] = module"; + children.setProperty(length, module); return true; - } else if (parent->isValid()) { - qCDebug(scriptengine_module) << "registerModuleWithParent -- unrecognized parent" << parent->toVariant().toString(); + } else if (parent.isValid()) { + qCDebug(scriptengine_module) << "registerModuleWithParent -- unrecognized parent" << parent.toVariant().toString(); } return false; } // creates a new JS "module" Object with default metadata properties -ScriptValuePointer ScriptManager::newModule(const QString& modulePath, const ScriptValuePointer& parent) { +ScriptValue ScriptManager::newModule(const QString& modulePath, const ScriptValue& parent) { auto closure = _engine->newObject(); auto exports = _engine->newObject(); auto module = _engine->newObject(); - qCDebug(scriptengine_module) << "newModule" << parent->property("filename")->toString(); + qCDebug(scriptengine_module) << "newModule" << parent.property("filename").toString(); - closure->setProperty("module", module, READONLY_PROP_FLAGS); + closure.setProperty("module", module, READONLY_PROP_FLAGS); // note: this becomes the "exports" free variable, so should not be set read only - closure->setProperty("exports", exports); + closure.setProperty("exports", exports); // make the closure available to module instantiation - module->setProperty("__closure__", closure, READONLY_HIDDEN_PROP_FLAGS); + module.setProperty("__closure__", closure, READONLY_HIDDEN_PROP_FLAGS); // for consistency with Node.js Module - module->setProperty("id", modulePath, READONLY_PROP_FLAGS); - module->setProperty("filename", modulePath, READONLY_PROP_FLAGS); - module->setProperty("exports", exports); // not readonly - module->setProperty("loaded", false, READONLY_PROP_FLAGS); - module->setProperty("parent", parent, READONLY_PROP_FLAGS); - module->setProperty("children", _engine->newArray(), READONLY_PROP_FLAGS); + module.setProperty("id", modulePath, READONLY_PROP_FLAGS); + module.setProperty("filename", modulePath, READONLY_PROP_FLAGS); + module.setProperty("exports", exports); // not readonly + module.setProperty("loaded", false, READONLY_PROP_FLAGS); + module.setProperty("parent", parent, READONLY_PROP_FLAGS); + module.setProperty("children", _engine->newArray(), READONLY_PROP_FLAGS); // module.require is a bound version of require that always resolves relative to that module's path auto boundRequire = _engine->evaluate("(function(id) { return Script.require(Script.require.resolve(id, this.filename)); })", "(boundRequire)"); - module->setProperty("require", boundRequire, READONLY_PROP_FLAGS); + module.setProperty("require", boundRequire, READONLY_PROP_FLAGS); return module; } @@ -1383,23 +1383,23 @@ QVariantMap ScriptManager::fetchModuleSource(const QString& modulePath, const bo } // evaluate a pending module object using the fetched source code -ScriptValuePointer ScriptManager::instantiateModule(const ScriptValuePointer& module, const QString& sourceCode) { - ScriptValuePointer result; - auto modulePath = module->property("filename")->toString(); - auto closure = module->property("__closure__"); +ScriptValue ScriptManager::instantiateModule(const ScriptValue& module, const QString& sourceCode) { + ScriptValue result; + auto modulePath = module.property("filename").toString(); + auto closure = module.property("__closure__"); qCDebug(scriptengine_module) << QString("require.instantiateModule: %1 / %2 bytes") .arg(QUrl(modulePath).fileName()).arg(sourceCode.length()); - if (module->property("content-type")->toString() == "application/json") { + if (module.property("content-type").toString() == "application/json") { qCDebug(scriptengine_module) << "... parsing as JSON"; - closure->setProperty("__json", sourceCode); + closure.setProperty("__json", sourceCode); result = _engine->evaluateInClosure(closure, _engine->newProgram( "module.exports = JSON.parse(__json)", modulePath )); } else { // scoped vars for consistency with Node.js - closure->setProperty("require", module->property("require")); - closure->setProperty("__filename", modulePath, READONLY_HIDDEN_PROP_FLAGS); - closure->setProperty("__dirname", QString(modulePath).replace(QRegExp("/[^/]*$"), ""), READONLY_HIDDEN_PROP_FLAGS); + closure.setProperty("require", module.property("require")); + closure.setProperty("__filename", modulePath, READONLY_HIDDEN_PROP_FLAGS); + closure.setProperty("__dirname", QString(modulePath).replace(QRegExp("/[^/]*$"), ""), READONLY_HIDDEN_PROP_FLAGS); result = _engine->evaluateInClosure(closure, _engine->newProgram( sourceCode, modulePath )); } _engine->maybeEmitUncaughtException(__FUNCTION__); @@ -1407,19 +1407,19 @@ ScriptValuePointer ScriptManager::instantiateModule(const ScriptValuePointer& mo } // CommonJS/Node.js like require/module support -ScriptValuePointer ScriptManager::require(const QString& moduleId) { +ScriptValue ScriptManager::require(const QString& moduleId) { qCDebug(scriptengine_module) << "ScriptManager::require(" << moduleId.left(MAX_DEBUG_VALUE_LENGTH) << ")"; if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return _engine->nullValue(); } - auto jsRequire = _engine->globalObject()->property("Script")->property("require"); + auto jsRequire = _engine->globalObject().property("Script").property("require"); auto cacheMeta = jsRequire.data(); - auto cache = jsRequire->property("cache"); + auto cache = jsRequire.property("cache"); auto parent = currentModule(); - auto throwModuleError = [&](const QString& modulePath, const ScriptValuePointer& error) { - cache->setProperty(modulePath, _engine->nullValue()); + auto throwModuleError = [&](const QString& modulePath, const ScriptValue& error) { + cache.setProperty(modulePath, _engine->nullValue()); if (!error.isNull()) { #ifdef DEBUG_JS_MODULES qCWarning(scriptengine_module) << "throwing module error:" << error.toString() << modulePath << error.property("stack").toString(); @@ -1439,7 +1439,7 @@ ScriptValuePointer ScriptManager::require(const QString& moduleId) { } // check the resolved path against the cache - auto module = cache->property(modulePath); + auto module = cache.property(modulePath); // modules get cached in `Script.require.cache` and (similar to Node.js) users can access it // to inspect particular entries and invalidate them by deleting the key: @@ -1449,16 +1449,16 @@ ScriptValuePointer ScriptManager::require(const QString& moduleId) { Setting::Handle getCachebustSetting {"cachebustScriptRequire", false }; // cacheMeta is just used right now to tell deleted keys apart from undefined ones - bool invalidateCache = getCachebustSetting.get() || (module->isUndefined() && cacheMeta->property(moduleId)->isValid()); + bool invalidateCache = getCachebustSetting.get() || (module.isUndefined() && cacheMeta.property(moduleId).isValid()); // reset the cacheMeta record so invalidation won't apply next time, even if the module fails to load - cacheMeta->setProperty(modulePath, ScriptValuePointer()); + cacheMeta.setProperty(modulePath, ScriptValue()); - auto exports = module->property("exports"); - if (!invalidateCache && exports->isObject()) { + auto exports = module.property("exports"); + if (!invalidateCache && exports.isObject()) { // we have found a cached module -- just need to possibly register it with current parent qCDebug(scriptengine_module) << QString("require - using cached module for '%1' (loaded: %2)") - .arg(moduleId).arg(module->property("loaded")->toString()); + .arg(moduleId).arg(module.property("loaded").toString()); registerModuleWithParent(module, parent); _engine->maybeEmitUncaughtException("cached module"); return exports; @@ -1469,7 +1469,7 @@ ScriptValuePointer ScriptManager::require(const QString& moduleId) { registerModuleWithParent(module, parent); // add it to the cache (this is done early so any cyclic dependencies pick up) - cache->setProperty(modulePath, module); + cache.setProperty(modulePath, module); // download the module source auto req = fetchModuleSource(modulePath, invalidateCache); @@ -1487,36 +1487,36 @@ ScriptValuePointer ScriptManager::require(const QString& moduleId) { auto sourceCode = req["contents"].toString(); if (QUrl(modulePath).fileName().endsWith(".json", Qt::CaseInsensitive)) { - module->setProperty("content-type", "application/json"); + module.setProperty("content-type", "application/json"); } else { - module->setProperty("content-type", "application/javascript"); + module.setProperty("content-type", "application/javascript"); } // evaluate the module auto result = instantiateModule(module, sourceCode); - if (result->isError() && !result->strictlyEquals(module->property("exports"))) { - qCWarning(scriptengine_module) << "-- result.isError --" << result->toString(); + if (result.isError() && !result.strictlyEquals(module.property("exports"))) { + qCWarning(scriptengine_module) << "-- result.isError --" << result.toString(); return throwModuleError(modulePath, result); } // mark as fully-loaded - module->setProperty("loaded", true, READONLY_PROP_FLAGS); + module.setProperty("loaded", true, READONLY_PROP_FLAGS); // set up a new reference point for detecting cache key deletion - cacheMeta->setProperty(modulePath, module); + cacheMeta.setProperty(modulePath, module); qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")"; _engine->maybeEmitUncaughtException(__FUNCTION__); - return module->property("exports"); + return module.property("exports"); } // If a callback is specified, the included files will be loaded asynchronously and the callback will be called // when all of the files have finished loading. // If no callback is specified, the included files will be loaded synchronously and will block execution until // all of the files have finished loading. -void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer callback) { +void ScriptManager::include(const QStringList& includeFiles, const ScriptValue& callback) { if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return; } @@ -1592,8 +1592,8 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer } _parentURL = parentURL; - if (callback && callback->isFunction()) { - callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, callback, ScriptValuePointer(), ScriptValueList()); + if (callback.isFunction()) { + callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, callback, ScriptValue(), ScriptValueList()); } loader->deleteLater(); @@ -1606,14 +1606,14 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer loader->start(processLevelMaxRetries); - if ((!callback || !callback->isFunction()) && !loader->isFinished()) { + if (!callback.isFunction() && !loader->isFinished()) { QEventLoop loop; QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit); loop.exec(); } } -void ScriptManager::include(const QString& includeFile, ScriptValuePointer callback) { +void ScriptManager::include(const QString& includeFile, const ScriptValue& callback) { if (isStopped()) { scriptWarningMessage("Script.include() while shutting down is ignored... includeFile:" + includeFile + "parent script:" + getFilename()); @@ -1654,7 +1654,7 @@ void ScriptManager::load(const QString& loadFile) { } // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args -void ScriptManager::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, ScriptValueList eventHandlerArgs) { +void ScriptManager::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, const ScriptValueList& eventHandlerArgs) { if (QThread::currentThread() != thread()) { qCDebug(scriptengine) << "*** ERROR *** ScriptManager::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; assert(false); @@ -1674,7 +1674,7 @@ void ScriptManager::forwardHandlerCall(const EntityItemID& entityID, const QStri // and the entity scripts may be for entities other than the one this is a handler for. // Fortunately, the definingEntityIdentifier captured the entity script id (if any) when the handler was added. CallbackData& handler = handlersForEvent[i]; - callWithEnvironment(handler.definingEntityIdentifier, handler.definingSandboxURL, handler.function, ScriptValuePointer(), eventHandlerArgs); + callWithEnvironment(handler.definingEntityIdentifier, handler.definingSandboxURL, handler.function, ScriptValue(), eventHandlerArgs); } } } @@ -1921,13 +1921,13 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c // SYNTAX ERRORS auto syntaxError = _engine->lintScript(contents, fileName); - if (syntaxError->isError()) { - auto message = syntaxError->property("formatted")->toString(); + if (syntaxError.isError()) { + auto message = syntaxError.property("formatted").toString(); if (message.isEmpty()) { - message = syntaxError->toString(); + message = syntaxError.toString(); } setError(QString("Bad syntax (%1)").arg(message), EntityScriptStatus::ERROR_RUNNING_SCRIPT); - syntaxError->setProperty("detail", entityID.toString()); + syntaxError.setProperty("detail", entityID.toString()); emit unhandledException(syntaxError); return; } @@ -1946,7 +1946,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c const int SANDBOX_TIMEOUT = 0.25 * MSECS_PER_SECOND; ScriptEnginePointer sandbox = newScriptEngine(); sandbox->setProcessEventsInterval(SANDBOX_TIMEOUT); - ScriptValuePointer testConstructor, exception; + ScriptValue testConstructor, exception; if (atoi(getenv("UNSAFE_ENTITY_SCRIPTS") ? getenv("UNSAFE_ENTITY_SCRIPTS") : "0")) { QTimer timeout; @@ -1966,7 +1966,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c if (sandbox->hasUncaughtException()) { exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); sandbox->clearExceptions(); - } else if (testConstructor && testConstructor->isError()) { + } else if (testConstructor.isError()) { exception = testConstructor; } } else { @@ -2041,7 +2041,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c if (sandbox->hasUncaughtException()) { exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); sandbox->clearExceptions(); - } else if (testConstructor && testConstructor->isError()) { + } else if (testConstructor.isError()) { exception = testConstructor; } } @@ -2051,7 +2051,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c // exception = makeError("UNSAFE_ENTITY_SCRIPTS == 0"); } - if (exception && exception->isError()) { + if (exception.isError()) { // create a local copy using makeError to decouple from the sandbox engine exception = _engine->makeError(exception); setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); @@ -2060,12 +2060,12 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c } // CONSTRUCTOR VIABILITY - if (!testConstructor || !testConstructor->isFunction()) { - QString testConstructorType = QString(testConstructor->toVariant().typeName()); + if (!testConstructor.isFunction()) { + QString testConstructorType = QString(testConstructor.toVariant().typeName()); if (testConstructorType == "") { testConstructorType = "empty"; } - QString testConstructorValue = testConstructor->toString(); + QString testConstructorValue = testConstructor.toString(); if (testConstructorValue.size() > MAX_DEBUG_VALUE_LENGTH) { testConstructorValue = testConstructorValue.mid(0, MAX_DEBUG_VALUE_LENGTH) + "..."; } @@ -2073,8 +2073,8 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c .arg(testConstructorType).arg(testConstructorValue); auto err = _engine->makeError(_engine->newValue(message)); - err->setProperty("fileName", scriptOrURL); - err->setProperty("detail", "(constructor " + entityID.toString() + ")"); + err.setProperty("fileName", scriptOrURL); + err.setProperty("detail", "(constructor " + entityID.toString() + ")"); setError("Could not find constructor (" + testConstructorType + ")", EntityScriptStatus::ERROR_RUNNING_SCRIPT); emit unhandledException(err); @@ -2089,11 +2089,11 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c } // THE ACTUAL EVALUATION AND CONSTRUCTION - ScriptValuePointer entityScriptConstructor, entityScriptObject; + ScriptValue entityScriptConstructor, entityScriptObject; QUrl sandboxURL = currentSandboxURL.isEmpty() ? scriptOrURL : currentSandboxURL; auto initialization = [&]{ entityScriptConstructor = _engine->evaluate(contents, fileName); - entityScriptObject = entityScriptConstructor->construct(); + entityScriptObject = entityScriptConstructor.construct(); if (_engine->hasUncaughtException()) { entityScriptObject = _engine->cloneUncaughtException("(construct " + entityID.toString() + ")"); @@ -2103,7 +2103,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c doWithEnvironment(entityID, sandboxURL, initialization); - if (entityScriptObject && entityScriptObject->isError()) { + if (entityScriptObject.isError()) { auto exception = entityScriptObject; setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); emit unhandledException(exception); @@ -2266,7 +2266,7 @@ void ScriptManager::doWithEnvironment(const EntityItemID& entityID, const QUrl& currentSandboxURL = sandboxURL; #if DEBUG_CURRENT_ENTITY - ScriptValuePointer oldData = this->globalObject().property("debugEntityID"); + ScriptValue oldData = this->globalObject().property("debugEntityID"); this->globalObject().setProperty("debugEntityID", entityID.toScriptValue(this)); // Make the entityID available to javascript as a global. operation(); this->globalObject().setProperty("debugEntityID", oldData); @@ -2278,9 +2278,9 @@ void ScriptManager::doWithEnvironment(const EntityItemID& entityID, const QUrl& currentSandboxURL = oldSandboxURL; } -void ScriptManager::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, ScriptValuePointer function, ScriptValuePointer thisObject, ScriptValueList args) { +void ScriptManager::callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, const ScriptValue& function, const ScriptValue& thisObject, const ScriptValueList& args) { auto operation = [&]() { - function->call(thisObject, args); + function.call(thisObject, args); }; doWithEnvironment(entityID, sandboxURL, operation); } @@ -2313,7 +2313,7 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q QWriteLocker locker { &_entityScriptsLock }; details = _entityScripts[entityID]; } - ScriptValuePointer entityScript = details.scriptObject; // previously loaded + ScriptValue entityScript = details.scriptObject; // previously loaded // If this is a remote call, we need to check to see if the function is remotely callable // we do this by checking for the existance of the 'remotelyCallable' property on the @@ -2323,11 +2323,11 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q if (remoteCallerID == QUuid()) { callAllowed = true; } else { - if (entityScript->property("remotelyCallable")->isArray()) { - auto callables = entityScript->property("remotelyCallable"); - auto callableCount = callables->property("length")->toInteger(); + if (entityScript.property("remotelyCallable").isArray()) { + auto callables = entityScript.property("remotelyCallable"); + auto callableCount = callables.property("length").toInteger(); for (int i = 0; i < callableCount; i++) { - auto callable = callables->property(i)->toString(); + auto callable = callables.property(i).toString(); if (callable == methodName) { callAllowed = true; break; @@ -2339,17 +2339,17 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q } } - if (callAllowed && entityScript->property(methodName)->isFunction()) { + if (callAllowed && entityScript.property(methodName).isFunction()) { auto scriptEngine = engine().data(); ScriptValueList args; args << EntityItemIDtoScriptValue(scriptEngine, entityID); args << scriptValueFromSequence(scriptEngine, params); - ScriptValuePointer oldData = scriptEngine->globalObject()->property("Script")->property("remoteCallerID"); - scriptEngine->globalObject()->property("Script")->setProperty("remoteCallerID", remoteCallerID.toString()); // Make the remoteCallerID available to javascript as a global. - callWithEnvironment(entityID, details.definingSandboxURL, entityScript->property(methodName), entityScript, args); - scriptEngine->globalObject()->property("Script")->setProperty("remoteCallerID", oldData); + ScriptValue oldData = scriptEngine->globalObject().property("Script").property("remoteCallerID"); + scriptEngine->globalObject().property("Script").setProperty("remoteCallerID", remoteCallerID.toString()); // Make the remoteCallerID available to javascript as a global. + callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); + scriptEngine->globalObject().property("Script").setProperty("remoteCallerID", oldData); } } } @@ -2381,14 +2381,14 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q QWriteLocker locker { &_entityScriptsLock }; details = _entityScripts[entityID]; } - ScriptValuePointer entityScript = details.scriptObject; // previously loaded - if (entityScript->property(methodName)->isFunction()) { + ScriptValue entityScript = details.scriptObject; // previously loaded + if (entityScript.property(methodName).isFunction()) { auto scriptEngine = engine().data(); ScriptValueList args; args << EntityItemIDtoScriptValue(scriptEngine, entityID); args << event.toScriptValue(scriptEngine); - callWithEnvironment(entityID, details.definingSandboxURL, entityScript->property(methodName), entityScript, args); + callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); } } } @@ -2421,15 +2421,15 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q QWriteLocker locker { &_entityScriptsLock }; details = _entityScripts[entityID]; } - ScriptValuePointer entityScript = details.scriptObject; // previously loaded - if (entityScript->property(methodName)->isFunction()) { + ScriptValue entityScript = details.scriptObject; // previously loaded + if (entityScript.property(methodName).isFunction()) { auto scriptEngine = engine().data(); ScriptValueList args; args << EntityItemIDtoScriptValue(scriptEngine, entityID); args << EntityItemIDtoScriptValue(scriptEngine, otherID); args << collisionToScriptValue(scriptEngine, collision); - callWithEnvironment(entityID, details.definingSandboxURL, entityScript->property(methodName), entityScript, args); + callWithEnvironment(entityID, details.definingSandboxURL, entityScript.property(methodName), entityScript, args); } } } @@ -2438,28 +2438,28 @@ QString ScriptManager::getExternalPath(ExternalResource::Bucket bucket, const QS return ExternalResource::getInstance()->getUrl(bucket, path); } -QString ScriptManager::formatException(const ScriptValuePointer& exception, bool includeExtendedDetails) { +QString ScriptManager::formatException(const ScriptValue& exception, bool includeExtendedDetails) { if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) { return QString(); } QString note{ "UncaughtException" }; QString result; - if (!exception->isObject()) { + if (!exception.isObject()) { return result; } - const auto message = exception->toString(); - const auto fileName = exception->property("fileName")->toString(); - const auto lineNumber = exception->property("lineNumber")->toString(); - const auto stacktrace = exception->property("stack")->toString(); + const auto message = exception.toString(); + const auto fileName = exception.property("fileName").toString(); + const auto lineNumber = exception.property("lineNumber").toString(); + const auto stacktrace = exception.property("stack").toString(); if (includeExtendedDetails) { // Display additional exception / troubleshooting hints that can be added via the custom Error .detail property // Example difference: // [UncaughtExceptions] Error: Can't find variable: foobar in atp:/myentity.js\n... // [UncaughtException (construct {1eb5d3fa-23b1-411c-af83-163af7220e3f})] Error: Can't find variable: foobar in atp:/myentity.js\n... - if (exception->property("detail")->isValid()) { - note += " " + exception->property("detail")->toString(); + if (exception.property("detail").isValid()) { + note += " " + exception.property("detail").toString(); } } @@ -2470,6 +2470,6 @@ QString ScriptManager::formatException(const ScriptValuePointer& exception, bool return result; } -ScriptValuePointer ScriptManager::evaluate(const QString& program, const QString& fileName) { +ScriptValue ScriptManager::evaluate(const QString& program, const QString& fileName) { return _engine->evaluate(program, fileName); } diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index 5b54623c2be..bf6cb36339c 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -45,6 +45,7 @@ #include "PointerEvent.h" #include "Quat.h" #include "ScriptUUID.h" +#include "ScriptValue.h" #include "Vec3.h" static const QString NO_SCRIPT(""); @@ -56,17 +57,15 @@ static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900; class ScriptEngine; class ScriptEngines; class ScriptManager; -class ScriptValue; using ScriptEnginePointer = QSharedPointer; using ScriptManagerPointer = QSharedPointer; -using ScriptValuePointer = QSharedPointer; -using ScriptValueList = QList; +using ScriptValueList = QList; Q_DECLARE_METATYPE(ScriptManagerPointer) class CallbackData { public: - ScriptValuePointer function; + ScriptValue function; EntityItemID definingEntityIdentifier; QUrl definingSandboxURL; }; @@ -100,7 +99,7 @@ class EntityScriptDetails { QString errorInfo { "" }; QString scriptText { "" }; - ScriptValuePointer scriptObject{ ScriptValuePointer() }; + ScriptValue scriptObject{ ScriptValue() }; int64_t lastModified { 0 }; QUrl definingSandboxURL { QUrl("about:EntityScript") }; }; @@ -290,7 +289,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * @returns {string} String. * @deprecated This function is deprecated and will be removed. */ - Q_INVOKABLE QString formatException(const ScriptValuePointer& exception, bool includeExtendedDetails); + Q_INVOKABLE QString formatException(const ScriptValue& exception, bool includeExtendedDetails); /*@jsdoc * Adds a function to the list of functions called when a particular event occurs on a particular entity. @@ -314,7 +313,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * * Script.addEventHandler(entityID, "mousePressOnEntity", reportMousePress); */ - Q_INVOKABLE void addEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler); + Q_INVOKABLE void addEventHandler(const EntityItemID& entityID, const QString& eventName, const ScriptValue& handler); /*@jsdoc * Removes a function from the list of functions called when an entity event occurs on a particular entity. @@ -324,7 +323,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * @param {Script.EntityEvent} eventName - The name of the entity event. * @param {function} handler - The name of the function to no longer call when the entity event occurs on the entity. */ - Q_INVOKABLE void removeEventHandler(const EntityItemID& entityID, const QString& eventName, ScriptValuePointer handler); + Q_INVOKABLE void removeEventHandler(const EntityItemID& entityID, const QString& eventName, const ScriptValue& handler); /*@jsdoc * Starts running another script in Interface, if it isn't already running. The script is not automatically loaded next @@ -358,7 +357,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * @param {function} [callback=null] - The function to call back when the scripts have been included. It can be either the * name of a function or an in-line definition. */ - Q_INVOKABLE void include(const QStringList& includeFiles, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void include(const QStringList& includeFiles, const ScriptValue& callback = ScriptValue()); /*@jsdoc * Includes JavaScript from another file in the current script. If a callback is specified, the file is loaded and included @@ -383,7 +382,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * // This is script A * // Script A has been included */ - Q_INVOKABLE void include(const QString& includeFile, ScriptValuePointer callback = ScriptValuePointer()); + Q_INVOKABLE void include(const QString& includeFile, const ScriptValue& callback = ScriptValue()); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // MODULE related methods @@ -397,7 +396,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * @returns {object|array} The value assigned to module.exports in the JavaScript file, or the value defined * in the JSON file. */ - Q_INVOKABLE ScriptValuePointer require(const QString& moduleId); + Q_INVOKABLE ScriptValue require(const QString& moduleId); /*@jsdoc * @function Script.resetModuleCache @@ -406,13 +405,13 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi */ Q_INVOKABLE void resetModuleCache(bool deleteScriptCache = false); - ScriptValuePointer currentModule(); - bool registerModuleWithParent(const ScriptValuePointer& module, const ScriptValuePointer& parent); - ScriptValuePointer newModule(const QString& modulePath, const ScriptValuePointer& parent = ScriptValuePointer()); + ScriptValue currentModule(); + bool registerModuleWithParent(const ScriptValue& module, const ScriptValue& parent); + ScriptValue newModule(const QString& modulePath, const ScriptValue& parent = ScriptValue()); QVariantMap fetchModuleSource(const QString& modulePath, const bool forceDownload = false); - ScriptValuePointer instantiateModule(const ScriptValuePointer& module, const QString& sourceCode); + ScriptValue instantiateModule(const ScriptValue& module, const QString& sourceCode); - Q_INVOKABLE ScriptValuePointer evaluate(const QString& program, const QString& fileName = QString()); + Q_INVOKABLE ScriptValue evaluate(const QString& program, const QString& fileName = QString()); /*@jsdoc * Calls a function repeatedly, at a set interval. @@ -425,7 +424,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * print("Interval timer fired"); * }, 1000); */ - Q_INVOKABLE QObject* setInterval(const ScriptValuePointer& function, int intervalMS); + Q_INVOKABLE QObject* setInterval(const ScriptValue& function, int intervalMS); /*@jsdoc * Calls a function once, after a delay. @@ -438,7 +437,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * print("Timeout timer fired"); * }, 1000); */ - Q_INVOKABLE QObject* setTimeout(const ScriptValuePointer& function, int timeoutMS); + Q_INVOKABLE QObject* setTimeout(const ScriptValue& function, int timeoutMS); /*@jsdoc * Stops an interval timer set by {@link Script.setInterval|setInterval}. @@ -634,7 +633,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi void setScriptEngines(QSharedPointer& scriptEngines) { _scriptEngines = scriptEngines; } // call all the registered event handlers on an entity for the specified name. - void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, ScriptValueList eventHanderArgs); + void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, const ScriptValueList& eventHanderArgs); // remove all event handlers for the specified entityID (i.e. the entity is being removed) void removeAllEventHandlers(const EntityItemID& entityID); @@ -857,7 +856,7 @@ public slots: * }); * var properties = JSON.parse("{ x: 1"); // Invalid JSON string. */ - void unhandledException(const ScriptValuePointer& exception); + void unhandledException(const ScriptValue& exception); // Triggered once before the first call to Script.addEventHandler happens on this ScriptManager // connections assumed to use Qt::DirectConnection; not for use by scripts @@ -889,7 +888,7 @@ public slots: // then inside of init() we just have to do "Script.require.resolve = Script._requireResolve;" Q_INVOKABLE QString _requireResolve(const QString& moduleId, const QString& relativeTo = QString()); - QString logException(const ScriptValuePointer& exception); + QString logException(const ScriptValue& exception); void timerFired(); void stopAllTimers(); void stopAllTimersForEntityScript(const EntityItemID& entityID); @@ -898,7 +897,7 @@ public slots: void setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details); void setParentURL(const QString& parentURL) { _parentURL = parentURL; } - QObject* setupTimerWithInterval(const ScriptValuePointer& function, int intervalMS, bool isSingleShot); + QObject* setupTimerWithInterval(const ScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); QHash _registeredHandlers; @@ -918,7 +917,7 @@ public slots: EntityItemID currentEntityIdentifier; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution. QUrl currentSandboxURL; // The toplevel url string for the entity script that loaded the code being executed, else empty. void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation); - void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, ScriptValuePointer function, ScriptValuePointer thisObject, ScriptValueList args); + void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, const ScriptValue& function, const ScriptValue& thisObject, const ScriptValueList& args); Context _context; Type _type; diff --git a/libraries/script-engine/src/ScriptValue.cpp b/libraries/script-engine/src/ScriptValue.cpp new file mode 100644 index 00000000000..344d9a6393e --- /dev/null +++ b/libraries/script-engine/src/ScriptValue.cpp @@ -0,0 +1,236 @@ +// +// ScriptValue.cpp +// libraries/script-engine/src +// +// Created by Heather Anderson on 9/2/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptValue.h" + +#include "ScriptEngineLogging.h" + + +class ScriptValueProxyNull : public ScriptValueProxy { +public: + virtual void release(); + virtual ScriptValueProxy* copy() const; + +public: + virtual ScriptValue call(const ScriptValue& thisObject = ScriptValue(), const ScriptValueList& args = ScriptValueList()); + virtual ScriptValue call(const ScriptValue& thisObject, const ScriptValue& arguments); + virtual ScriptValue construct(const ScriptValueList& args = ScriptValueList()); + virtual ScriptValue construct(const ScriptValue& arguments); + virtual ScriptValue data() const; + virtual ScriptEnginePointer engine() const; + virtual bool equals(const ScriptValue& other) const; + virtual bool isArray() const; + virtual bool isBool() const; + virtual bool isError() const; + virtual bool isFunction() const; + virtual bool isNumber() const; + virtual bool isNull() const; + virtual bool isObject() const; + virtual bool isString() const; + virtual bool isUndefined() const; + virtual bool isValid() const; + virtual bool isVariant() const; + virtual ScriptValueIteratorPointer newIterator() const; + virtual ScriptValue property(const QString& name, + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const; + virtual ScriptValue property(quint32 arrayIndex, + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const; + virtual void setData(const ScriptValue& val); + virtual void setProperty(const QString& name, + const ScriptValue& value, + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags); + virtual void setProperty(quint32 arrayIndex, + const ScriptValue& value, + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags); + virtual void setPrototype(const ScriptValue& prototype); + virtual bool strictlyEquals(const ScriptValue& other) const; + + virtual bool toBool() const; + virtual qint32 toInt32() const; + virtual double toInteger() const; + virtual double toNumber() const; + virtual QString toString() const; + virtual quint16 toUInt16() const; + virtual quint32 toUInt32() const; + virtual QVariant toVariant() const; + virtual QObject* toQObject() const; +}; + +static ScriptValueProxyNull SCRIPT_VALUE_NULL; + +ScriptValue::ScriptValue() : _proxy(&SCRIPT_VALUE_NULL) {} + +void ScriptValueProxyNull::release() { + // do nothing, we're a singlet +} + +ScriptValueProxy* ScriptValueProxyNull::copy() const { + // return ourselves, we're a singlet + return const_cast (this); +} + +ScriptValue ScriptValueProxyNull::call(const ScriptValue& thisObject, const ScriptValueList& args) { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::call made to empty value"); + return ScriptValue(); +} + +ScriptValue ScriptValueProxyNull::call(const ScriptValue& thisObject, const ScriptValue& arguments) { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::call made to empty value"); + return ScriptValue(); +} + +ScriptValue ScriptValueProxyNull::construct(const ScriptValueList& args) { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::construct called on empty value"); + return ScriptValue(); +} + +ScriptValue ScriptValueProxyNull::construct(const ScriptValue& arguments) { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::construct called on empty value"); + return ScriptValue(); +} + +ScriptValue ScriptValueProxyNull::data() const { + return ScriptValue(); +} + +ScriptEnginePointer ScriptValueProxyNull::engine() const { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::engine called on empty value"); + return ScriptEnginePointer(); +} + +bool ScriptValueProxyNull::equals(const ScriptValue& other) const { + return other.isUndefined(); +} + +bool ScriptValueProxyNull::isArray() const { + return false; +} + +bool ScriptValueProxyNull::isBool() const { + return false; +} + +bool ScriptValueProxyNull::isError() const { + return false; +} + +bool ScriptValueProxyNull::isFunction() const { + return false; +} + +bool ScriptValueProxyNull::isNumber() const { + return false; +} + +bool ScriptValueProxyNull::isNull() const { + return false; +} + +bool ScriptValueProxyNull::isObject() const { + return false; +} + +bool ScriptValueProxyNull::isString() const { + return false; +} + +bool ScriptValueProxyNull::isUndefined() const { + return true; +} + +bool ScriptValueProxyNull::isValid() const { + return false; +} + +bool ScriptValueProxyNull::isVariant() const { + return false; +} + +ScriptValueIteratorPointer ScriptValueProxyNull::newIterator() const { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::newIterator called on empty value"); + return ScriptValueIteratorPointer(); +} + +ScriptValue ScriptValueProxyNull::property(const QString& name, const ScriptValue::ResolveFlags& mode) const { + return ScriptValue(); +} + +ScriptValue ScriptValueProxyNull::property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode) const { + return ScriptValue(); +} + +void ScriptValueProxyNull::setData(const ScriptValue& val) { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::setData called on empty value"); +} + +void ScriptValueProxyNull::setProperty(const QString& name, + const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::setProperty called on empty value"); +} + +void ScriptValueProxyNull::setProperty(quint32 arrayIndex, + const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::setProperty called on empty value"); +} + +void ScriptValueProxyNull::setPrototype(const ScriptValue& prototype) { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::setPrototype called on empty value"); +} + +bool ScriptValueProxyNull::strictlyEquals(const ScriptValue& other) const { + return !other.isValid(); +} + +bool ScriptValueProxyNull::toBool() const { + return false; +} + +qint32 ScriptValueProxyNull::toInt32() const { + return 0; +} + +double ScriptValueProxyNull::toInteger() const { + return 0; +} + +double ScriptValueProxyNull::toNumber() const { + return 0; +} + +QString ScriptValueProxyNull::toString() const { + return QString(); +} + +quint16 ScriptValueProxyNull::toUInt16() const { + return 0; +} + +quint32 ScriptValueProxyNull::toUInt32() const { + return 0; +} + +QVariant ScriptValueProxyNull::toVariant() const { + return QVariant(); +} + +QObject* ScriptValueProxyNull::toQObject() const { + return nullptr; +} diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h index 7b774045460..e2c608b8fcc 100644 --- a/libraries/script-engine/src/ScriptValue.h +++ b/libraries/script-engine/src/ScriptValue.h @@ -15,18 +15,19 @@ #ifndef hifi_ScriptValue_h #define hifi_ScriptValue_h +#include #include #include #include #include +#include -class QObject; class ScriptEngine; class ScriptValue; class ScriptValueIterator; +class ScriptValueProxy; using ScriptEnginePointer = QSharedPointer; -using ScriptValuePointer = QSharedPointer; -using ScriptValueList = QList; +using ScriptValueList = QList; using ScriptValueIteratorPointer = QSharedPointer; /// [ScriptInterface] Provides an engine-independent interface for QScriptValue @@ -51,14 +52,22 @@ class ScriptValue { Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag); public: - virtual ScriptValuePointer call(const ScriptValuePointer& thisObject = ScriptValuePointer(), - const ScriptValueList& args = ScriptValueList()) = 0; - virtual ScriptValuePointer call(const ScriptValuePointer& thisObject, const ScriptValuePointer& arguments) = 0; - virtual ScriptValuePointer construct(const ScriptValueList& args = ScriptValueList()) = 0; - virtual ScriptValuePointer construct(const ScriptValuePointer& arguments) = 0; - virtual ScriptValuePointer data() const = 0; - virtual ScriptEnginePointer engine() const = 0; - inline bool equals(const ScriptValuePointer& other) const; + ScriptValue(); + inline ScriptValue(const ScriptValue& src); + inline ~ScriptValue(); + inline ScriptValue(ScriptValueProxy* proxy) : _proxy(proxy) {} + inline ScriptValueProxy* ptr() const { return _proxy; } + inline ScriptValue& operator=(const ScriptValue& other); + +public: + inline ScriptValue call(const ScriptValue& thisObject = ScriptValue(), + const ScriptValueList& args = ScriptValueList()) const; + inline ScriptValue call(const ScriptValue& thisObject, const ScriptValue& arguments) const; + inline ScriptValue construct(const ScriptValueList& args = ScriptValueList()) const; + inline ScriptValue construct(const ScriptValue& arguments) const; + inline ScriptValue data() const; + inline ScriptEnginePointer engine() const; + inline bool equals(const ScriptValue& other) const; inline bool isArray() const; inline bool isBool() const; inline bool isError() const; @@ -70,22 +79,80 @@ class ScriptValue { inline bool isUndefined() const; inline bool isValid() const; inline bool isVariant() const; - virtual ScriptValueIteratorPointer newIterator() = 0; - virtual ScriptValuePointer property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const = 0; - virtual ScriptValuePointer property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const = 0; - virtual void setData(const ScriptValuePointer& val) = 0; - virtual void setProperty(const QString& name, - const ScriptValuePointer& value, - const PropertyFlags& flags = KeepExistingFlags) = 0; - virtual void setProperty(quint32 arrayIndex, - const ScriptValuePointer& value, - const PropertyFlags& flags = KeepExistingFlags) = 0; - template void setProperty(const QString& name, const TYP& value, + inline ScriptValueIteratorPointer newIterator() const; + inline ScriptValue property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const; + inline ScriptValue property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const; + inline void setData(const ScriptValue& val); + inline void setProperty(const QString& name, + const ScriptValue& value, + const PropertyFlags& flags = KeepExistingFlags); + inline void setProperty(quint32 arrayIndex, + const ScriptValue& value, const PropertyFlags& flags = KeepExistingFlags); - template void setProperty(quint32 arrayIndex, const TYP& value, + template + inline void setProperty(const QString& name, const TYP& value, const PropertyFlags& flags = KeepExistingFlags); - virtual void setPrototype(const ScriptValuePointer& prototype) = 0; - virtual bool strictlyEquals(const ScriptValuePointer& other) const = 0; + template + inline void setProperty(quint32 arrayIndex, const TYP& value, + const PropertyFlags& flags = KeepExistingFlags); + inline void setPrototype(const ScriptValue& prototype); + inline bool strictlyEquals(const ScriptValue& other) const; + + inline bool toBool() const; + inline qint32 toInt32() const; + inline double toInteger() const; + inline double toNumber() const; + inline QString toString() const; + inline quint16 toUInt16() const; + inline quint32 toUInt32() const; + inline QVariant toVariant() const; + inline QObject* toQObject() const; + +protected: + ScriptValueProxy* _proxy; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptValue::PropertyFlags); + +/// [ScriptInterface] Provides an engine-independent interface for QScriptValue +class ScriptValueProxy { +public: + virtual void release() = 0; + virtual ScriptValueProxy* copy() const = 0; + +public: + virtual ScriptValue call(const ScriptValue& thisObject = ScriptValue(), + const ScriptValueList& args = ScriptValueList()) = 0; + virtual ScriptValue call(const ScriptValue& thisObject, const ScriptValue& arguments) = 0; + virtual ScriptValue construct(const ScriptValueList& args = ScriptValueList()) = 0; + virtual ScriptValue construct(const ScriptValue& arguments) = 0; + virtual ScriptValue data() const = 0; + virtual ScriptEnginePointer engine() const = 0; + virtual bool equals(const ScriptValue& other) const = 0; + virtual bool isArray() const = 0; + virtual bool isBool() const = 0; + virtual bool isError() const = 0; + virtual bool isFunction() const = 0; + virtual bool isNumber() const = 0; + virtual bool isNull() const = 0; + virtual bool isObject() const = 0; + virtual bool isString() const = 0; + virtual bool isUndefined() const = 0; + virtual bool isValid() const = 0; + virtual bool isVariant() const = 0; + virtual ScriptValueIteratorPointer newIterator() const = 0; + virtual ScriptValue property(const QString& name, + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const = 0; + virtual ScriptValue property(quint32 arrayIndex, + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const = 0; + virtual void setData(const ScriptValue& val) = 0; + virtual void setProperty(const QString& name, + const ScriptValue& value, + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) = 0; + virtual void setProperty(quint32 arrayIndex, + const ScriptValue& value, + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) = 0; + virtual void setPrototype(const ScriptValue& prototype) = 0; + virtual bool strictlyEquals(const ScriptValue& other) const = 0; virtual bool toBool() const = 0; virtual qint32 toInt32() const = 0; @@ -96,118 +163,170 @@ class ScriptValue { virtual quint32 toUInt32() const = 0; virtual QVariant toVariant() const = 0; virtual QObject* toQObject() const = 0; - -protected: - virtual bool equalsInternal(const ScriptValuePointer& other) const = 0; - virtual bool isArrayInternal() const = 0; - virtual bool isBoolInternal() const = 0; - virtual bool isErrorInternal() const = 0; - virtual bool isFunctionInternal() const = 0; - virtual bool isNumberInternal() const = 0; - virtual bool isNullInternal() const = 0; - virtual bool isObjectInternal() const = 0; - virtual bool isStringInternal() const = 0; - virtual bool isUndefinedInternal() const = 0; - virtual bool isValidInternal() const = 0; - virtual bool isVariantInternal() const = 0; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptValue::PropertyFlags); -bool ScriptValue::equals(const ScriptValuePointer& other) const { - if (this == NULL || !other) { - return (this == NULL) == !other; - } - return equalsInternal(other); +template +void ScriptValue::setProperty(const QString& name, const TYP& value, const PropertyFlags& flags) { + setProperty(name, engine()->newValue(value), flags); +} + +template +void ScriptValue::setProperty(quint32 arrayIndex, const TYP& value, const PropertyFlags& flags) { + setProperty(arrayIndex, engine()->newValue(value), flags); +} + +ScriptValue::ScriptValue(const ScriptValue& src) : _proxy(src.ptr()->copy()) { +} + +ScriptValue::~ScriptValue() { + _proxy->release(); +} + +ScriptValue& ScriptValue::operator=(const ScriptValue& other) { + _proxy->release(); + _proxy = other.ptr()->copy(); + return *this; +} + +ScriptValue ScriptValue::call(const ScriptValue& thisObject, const ScriptValueList& args) const { + return _proxy->call(thisObject, args); +} + +ScriptValue ScriptValue::call(const ScriptValue& thisObject, const ScriptValue& arguments) const { + return _proxy->call(thisObject, arguments); +} + +ScriptValue ScriptValue::construct(const ScriptValueList& args) const { + return _proxy->construct(args); +} + +ScriptValue ScriptValue::construct(const ScriptValue& arguments) const { + return _proxy->construct(arguments); +} + +ScriptValue ScriptValue::data() const { + return _proxy->data(); +} + +ScriptEnginePointer ScriptValue::engine() const { + return _proxy->engine(); +} + +bool ScriptValue::equals(const ScriptValue& other) const { + return _proxy->equals(other); } bool ScriptValue::isArray() const { - assert(this != NULL); - if (this == NULL) return false; - return isArrayInternal(); + return _proxy->isArray(); } bool ScriptValue::isBool() const { - assert(this != NULL); - if (this == NULL) - return false; - return isBoolInternal(); + return _proxy->isBool(); } bool ScriptValue::isError() const { - assert(this != NULL); - if (this == NULL) - return false; - return isErrorInternal(); + return _proxy->isError(); } bool ScriptValue::isFunction() const { - assert(this != NULL); - if (this == NULL) - return false; - return isFunctionInternal(); + return _proxy->isFunction(); } bool ScriptValue::isNumber() const { - assert(this != NULL); - if (this == NULL) - return false; - return isNumberInternal(); + return _proxy->isNumber(); } bool ScriptValue::isNull() const { - assert(this != NULL); - if (this == NULL) - return false; - return isNullInternal(); + return _proxy->isNull(); } bool ScriptValue::isObject() const { - assert(this != NULL); - if (this == NULL) - return false; - return isObjectInternal(); + return _proxy->isObject(); } bool ScriptValue::isString() const { - assert(this != NULL); - if (this == NULL) - return false; - return isStringInternal(); + return _proxy->isString(); } bool ScriptValue::isUndefined() const { - assert(this != NULL); - if (this == NULL) - return true; - return isUndefinedInternal(); + return _proxy->isUndefined(); } bool ScriptValue::isValid() const { - assert(this != NULL); - if (this == NULL) - return false; - return isValidInternal(); + return _proxy->isValid(); } bool ScriptValue::isVariant() const { - assert(this != NULL); - if (this == NULL) - return false; - return isVariantInternal(); + return _proxy->isVariant(); } -template -void ScriptValue::setProperty(const QString& name, const TYP& value, const PropertyFlags& flags) { - setProperty(name, engine()->newValue(value), flags); +ScriptValueIteratorPointer ScriptValue::newIterator() const { + return _proxy->newIterator(); } -template -void ScriptValue::setProperty(quint32 arrayIndex, const TYP& value, const PropertyFlags& flags) { - setProperty(arrayIndex, engine()->newValue(value), flags); +ScriptValue ScriptValue::property(const QString& name, const ResolveFlags& mode) const { + return _proxy->property(name, mode); +} + +ScriptValue ScriptValue::property(quint32 arrayIndex, const ResolveFlags& mode) const { + return _proxy->property(arrayIndex, mode); +} + +void ScriptValue::setData(const ScriptValue& val) { + return _proxy->setData(val); +} + +void ScriptValue::setProperty(const QString& name, const ScriptValue& value, const PropertyFlags& flags) { + return _proxy->setProperty(name, value, flags); +} + +void ScriptValue::setProperty(quint32 arrayIndex, const ScriptValue& value, const PropertyFlags& flags) { + return _proxy->setProperty(arrayIndex, value, flags); } -template -T scriptvalue_cast(const ScriptValuePointer& value); +void ScriptValue::setPrototype(const ScriptValue& prototype) { + return _proxy->setPrototype(prototype); +} + +bool ScriptValue::strictlyEquals(const ScriptValue& other) const { + return _proxy->strictlyEquals(other); +} + +bool ScriptValue::toBool() const { + return _proxy->toBool(); +} + +qint32 ScriptValue::toInt32() const { + return _proxy->toInt32(); +} + +double ScriptValue::toInteger() const { + return _proxy->toInteger(); +} + +double ScriptValue::toNumber() const { + return _proxy->toNumber(); +} + +QString ScriptValue::toString() const { + return _proxy->toString(); +} + +quint16 ScriptValue::toUInt16() const { + return _proxy->toUInt16(); +} + +quint32 ScriptValue::toUInt32() const { + return _proxy->toUInt32(); +} + +QVariant ScriptValue::toVariant() const { + return _proxy->toVariant(); +} + +QObject* ScriptValue::toQObject() const { + return _proxy->toQObject(); +} #endif // hifi_ScriptValue_h diff --git a/libraries/script-engine/src/ScriptValueIterator.h b/libraries/script-engine/src/ScriptValueIterator.h index 2222a457a86..6b383b8ae54 100644 --- a/libraries/script-engine/src/ScriptValueIterator.h +++ b/libraries/script-engine/src/ScriptValueIterator.h @@ -30,7 +30,7 @@ class ScriptValueIterator { virtual bool hasNext() const = 0; virtual QString name() const = 0; virtual void next() = 0; - virtual ScriptValuePointer value() const = 0; + virtual ScriptValue value() const = 0; }; #endif // hifi_ScriptValueIterator_h diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp index 4f52eb5572e..4b5775d9028 100644 --- a/libraries/script-engine/src/ScriptValueUtils.cpp +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -28,19 +28,19 @@ #include "ScriptEngineCast.h" #include "ScriptValueIterator.h" -bool isListOfStrings(const ScriptValuePointer& arg) { - if (!arg->isArray()) { +bool isListOfStrings(const ScriptValue& arg) { + if (!arg.isArray()) { return false; } - auto lengthProperty = arg->property("length"); - if (!lengthProperty->isNumber()) { + auto lengthProperty = arg.property("length"); + if (!lengthProperty.isNumber()) { return false; } - int length = lengthProperty->toInt32(); + int length = lengthProperty.toInt32(); for (int i = 0; i < length; i++) { - if (!arg->property(i)->isString()) { + if (!arg.property(i).isString()) { return false; } } @@ -80,9 +80,9 @@ void registerMetaTypes(ScriptEngine* engine) { scriptRegisterSequenceMetaType>(engine); } -ScriptValuePointer vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2) { - auto prototype = engine->globalObject()->property("__hifi_vec2__"); - if (!prototype->property("defined")->toBool()) { +ScriptValue vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2) { + auto prototype = engine->globalObject().property("__hifi_vec2__"); + if (!prototype.property("defined").toBool()) { prototype = engine->evaluate( "__hifi_vec2__ = Object.defineProperties({}, { " "defined: { value: true }," @@ -92,41 +92,41 @@ ScriptValuePointer vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2 "v: { set: function(nv) { return this.y = nv; }, get: function() { return this.y; } }" "})"); } - ScriptValuePointer value = engine->newObject(); - value->setProperty("x", vec2.x); - value->setProperty("y", vec2.y); - value->setPrototype(prototype); + ScriptValue value = engine->newObject(); + value.setProperty("x", vec2.x); + value.setProperty("y", vec2.y); + value.setPrototype(prototype); return value; } -void vec2FromScriptValue(const ScriptValuePointer& object, glm::vec2& vec2) { - if (object->isNumber()) { - vec2 = glm::vec2(object->toVariant().toFloat()); - } else if (object->isArray()) { - QVariantList list = object->toVariant().toList(); +void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2) { + if (object.isNumber()) { + vec2 = glm::vec2(object.toVariant().toFloat()); + } else if (object.isArray()) { + QVariantList list = object.toVariant().toList(); if (list.length() == 2) { vec2.x = list[0].toFloat(); vec2.y = list[1].toFloat(); } } else { - ScriptValuePointer x = object->property("x"); - if (!x->isValid()) { - x = object->property("u"); + ScriptValue x = object.property("x"); + if (!x.isValid()) { + x = object.property("u"); } - ScriptValuePointer y = object->property("y"); - if (!y->isValid()) { - y = object->property("v"); + ScriptValue y = object.property("y"); + if (!y.isValid()) { + y = object.property("v"); } - vec2.x = x->toVariant().toFloat(); - vec2.y = y->toVariant().toFloat(); + vec2.x = x.toVariant().toFloat(); + vec2.y = y.toVariant().toFloat(); } } -ScriptValuePointer vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) { - auto prototype = engine->globalObject()->property("__hifi_vec3__"); - if (!prototype->property("defined")->toBool()) { +ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) { + auto prototype = engine->globalObject().property("__hifi_vec3__"); + if (!prototype.property("defined").toBool()) { prototype = engine->evaluate( "__hifi_vec3__ = Object.defineProperties({}, { " "defined: { value: true }," @@ -141,17 +141,17 @@ ScriptValuePointer vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3 "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }" "})"); } - ScriptValuePointer value = engine->newObject(); - value->setProperty("x", vec3.x); - value->setProperty("y", vec3.y); - value->setProperty("z", vec3.z); - value->setPrototype(prototype); + ScriptValue value = engine->newObject(); + value.setProperty("x", vec3.x); + value.setProperty("y", vec3.y); + value.setProperty("z", vec3.z); + value.setPrototype(prototype); return value; } -ScriptValuePointer vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) { - auto prototype = engine->globalObject()->property("__hifi_vec3_color__"); - if (!prototype->property("defined")->toBool()) { +ScriptValue vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) { + auto prototype = engine->globalObject().property("__hifi_vec3_color__"); + if (!prototype.property("defined").toBool()) { prototype = engine->evaluate( "__hifi_vec3_color__ = Object.defineProperties({}, { " "defined: { value: true }," @@ -166,65 +166,65 @@ ScriptValuePointer vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }" "})"); } - ScriptValuePointer value = engine->newObject(); - value->setProperty("red", vec3.x); - value->setProperty("green", vec3.y); - value->setProperty("blue", vec3.z); - value->setPrototype(prototype); + ScriptValue value = engine->newObject(); + value.setProperty("red", vec3.x); + value.setProperty("green", vec3.y); + value.setProperty("blue", vec3.z); + value.setPrototype(prototype); return value; } -void vec3FromScriptValue(const ScriptValuePointer& object, glm::vec3& vec3) { - if (object->isNumber()) { - vec3 = glm::vec3(object->toVariant().toFloat()); - } else if (object->isString()) { - QColor qColor(object->toString()); +void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) { + if (object.isNumber()) { + vec3 = glm::vec3(object.toVariant().toFloat()); + } else if (object.isString()) { + QColor qColor(object.toString()); if (qColor.isValid()) { vec3.x = qColor.red(); vec3.y = qColor.green(); vec3.z = qColor.blue(); } - } else if (object->isArray()) { - QVariantList list = object->toVariant().toList(); + } else if (object.isArray()) { + QVariantList list = object.toVariant().toList(); if (list.length() == 3) { vec3.x = list[0].toFloat(); vec3.y = list[1].toFloat(); vec3.z = list[2].toFloat(); } } else { - ScriptValuePointer x = object->property("x"); - if (!x->isValid()) { - x = object->property("r"); + ScriptValue x = object.property("x"); + if (!x.isValid()) { + x = object.property("r"); } - if (!x->isValid()) { - x = object->property("red"); + if (!x.isValid()) { + x = object.property("red"); } - ScriptValuePointer y = object->property("y"); - if (!y->isValid()) { - y = object->property("g"); + ScriptValue y = object.property("y"); + if (!y.isValid()) { + y = object.property("g"); } - if (!y->isValid()) { - y = object->property("green"); + if (!y.isValid()) { + y = object.property("green"); } - ScriptValuePointer z = object->property("z"); - if (!z->isValid()) { - z = object->property("b"); + ScriptValue z = object.property("z"); + if (!z.isValid()) { + z = object.property("b"); } - if (!z->isValid()) { - z = object->property("blue"); + if (!z.isValid()) { + z = object.property("blue"); } - vec3.x = x->toVariant().toFloat(); - vec3.y = y->toVariant().toFloat(); - vec3.z = z->toVariant().toFloat(); + vec3.x = x.toVariant().toFloat(); + vec3.y = y.toVariant().toFloat(); + vec3.z = z.toVariant().toFloat(); } } -ScriptValuePointer u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) { - auto prototype = engine->globalObject()->property("__hifi_u8vec3__"); - if (!prototype->property("defined")->toBool()) { +ScriptValue u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) { + auto prototype = engine->globalObject().property("__hifi_u8vec3__"); + if (!prototype.property("defined").toBool()) { prototype = engine->evaluate( "__hifi_u8vec3__ = Object.defineProperties({}, { " "defined: { value: true }," @@ -239,17 +239,17 @@ ScriptValuePointer u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& "blue: { set: function(nv) { return this.z = nv; }, get: function() { return this.z; } }" "})"); } - ScriptValuePointer value = engine->newObject(); - value->setProperty("x", vec3.x); - value->setProperty("y", vec3.y); - value->setProperty("z", vec3.z); - value->setPrototype(prototype); + ScriptValue value = engine->newObject(); + value.setProperty("x", vec3.x); + value.setProperty("y", vec3.y); + value.setProperty("z", vec3.z); + value.setPrototype(prototype); return value; } -ScriptValuePointer u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) { - auto prototype = engine->globalObject()->property("__hifi_u8vec3_color__"); - if (!prototype->property("defined")->toBool()) { +ScriptValue u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) { + auto prototype = engine->globalObject().property("__hifi_u8vec3_color__"); + if (!prototype.property("defined").toBool()) { prototype = engine->evaluate( "__hifi_u8vec3_color__ = Object.defineProperties({}, { " "defined: { value: true }," @@ -264,174 +264,174 @@ ScriptValuePointer u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8v "z: { set: function(nv) { return this.blue = nv; }, get: function() { return this.blue; } }" "})"); } - ScriptValuePointer value = engine->newObject(); - value->setProperty("red", vec3.x); - value->setProperty("green", vec3.y); - value->setProperty("blue", vec3.z); - value->setPrototype(prototype); + ScriptValue value = engine->newObject(); + value.setProperty("red", vec3.x); + value.setProperty("green", vec3.y); + value.setProperty("blue", vec3.z); + value.setPrototype(prototype); return value; } -void u8vec3FromScriptValue(const ScriptValuePointer& object, glm::u8vec3& vec3) { - if (object->isNumber()) { - vec3 = glm::vec3(object->toVariant().toUInt()); - } else if (object->isString()) { - QColor qColor(object->toString()); +void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3) { + if (object.isNumber()) { + vec3 = glm::vec3(object.toVariant().toUInt()); + } else if (object.isString()) { + QColor qColor(object.toString()); if (qColor.isValid()) { vec3.x = (uint8_t)qColor.red(); vec3.y = (uint8_t)qColor.green(); vec3.z = (uint8_t)qColor.blue(); } - } else if (object->isArray()) { - QVariantList list = object->toVariant().toList(); + } else if (object.isArray()) { + QVariantList list = object.toVariant().toList(); if (list.length() == 3) { vec3.x = list[0].toUInt(); vec3.y = list[1].toUInt(); vec3.z = list[2].toUInt(); } } else { - ScriptValuePointer x = object->property("x"); - if (!x->isValid()) { - x = object->property("r"); + ScriptValue x = object.property("x"); + if (!x.isValid()) { + x = object.property("r"); } - if (!x->isValid()) { - x = object->property("red"); + if (!x.isValid()) { + x = object.property("red"); } - ScriptValuePointer y = object->property("y"); - if (!y->isValid()) { - y = object->property("g"); + ScriptValue y = object.property("y"); + if (!y.isValid()) { + y = object.property("g"); } - if (!y->isValid()) { - y = object->property("green"); + if (!y.isValid()) { + y = object.property("green"); } - ScriptValuePointer z = object->property("z"); - if (!z->isValid()) { - z = object->property("b"); + ScriptValue z = object.property("z"); + if (!z.isValid()) { + z = object.property("b"); } - if (!z->isValid()) { - z = object->property("blue"); + if (!z.isValid()) { + z = object.property("blue"); } - vec3.x = x->toVariant().toUInt(); - vec3.y = y->toVariant().toUInt(); - vec3.z = z->toVariant().toUInt(); + vec3.x = x.toVariant().toUInt(); + vec3.y = y.toVariant().toUInt(); + vec3.z = z.toVariant().toUInt(); } } -ScriptValuePointer vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("x", vec4.x); - obj->setProperty("y", vec4.y); - obj->setProperty("z", vec4.z); - obj->setProperty("w", vec4.w); +ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) { + ScriptValue obj = engine->newObject(); + obj.setProperty("x", vec4.x); + obj.setProperty("y", vec4.y); + obj.setProperty("z", vec4.z); + obj.setProperty("w", vec4.w); return obj; } -void vec4FromScriptValue(const ScriptValuePointer& object, glm::vec4& vec4) { - vec4.x = object->property("x")->toVariant().toFloat(); - vec4.y = object->property("y")->toVariant().toFloat(); - vec4.z = object->property("z")->toVariant().toFloat(); - vec4.w = object->property("w")->toVariant().toFloat(); -} - -ScriptValuePointer mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("r0c0", mat4[0][0]); - obj->setProperty("r1c0", mat4[0][1]); - obj->setProperty("r2c0", mat4[0][2]); - obj->setProperty("r3c0", mat4[0][3]); - obj->setProperty("r0c1", mat4[1][0]); - obj->setProperty("r1c1", mat4[1][1]); - obj->setProperty("r2c1", mat4[1][2]); - obj->setProperty("r3c1", mat4[1][3]); - obj->setProperty("r0c2", mat4[2][0]); - obj->setProperty("r1c2", mat4[2][1]); - obj->setProperty("r2c2", mat4[2][2]); - obj->setProperty("r3c2", mat4[2][3]); - obj->setProperty("r0c3", mat4[3][0]); - obj->setProperty("r1c3", mat4[3][1]); - obj->setProperty("r2c3", mat4[3][2]); - obj->setProperty("r3c3", mat4[3][3]); +void vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4) { + vec4.x = object.property("x").toVariant().toFloat(); + vec4.y = object.property("y").toVariant().toFloat(); + vec4.z = object.property("z").toVariant().toFloat(); + vec4.w = object.property("w").toVariant().toFloat(); +} + +ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) { + ScriptValue obj = engine->newObject(); + obj.setProperty("r0c0", mat4[0][0]); + obj.setProperty("r1c0", mat4[0][1]); + obj.setProperty("r2c0", mat4[0][2]); + obj.setProperty("r3c0", mat4[0][3]); + obj.setProperty("r0c1", mat4[1][0]); + obj.setProperty("r1c1", mat4[1][1]); + obj.setProperty("r2c1", mat4[1][2]); + obj.setProperty("r3c1", mat4[1][3]); + obj.setProperty("r0c2", mat4[2][0]); + obj.setProperty("r1c2", mat4[2][1]); + obj.setProperty("r2c2", mat4[2][2]); + obj.setProperty("r3c2", mat4[2][3]); + obj.setProperty("r0c3", mat4[3][0]); + obj.setProperty("r1c3", mat4[3][1]); + obj.setProperty("r2c3", mat4[3][2]); + obj.setProperty("r3c3", mat4[3][3]); return obj; } -void mat4FromScriptValue(const ScriptValuePointer& object, glm::mat4& mat4) { - mat4[0][0] = object->property("r0c0")->toVariant().toFloat(); - mat4[0][1] = object->property("r1c0")->toVariant().toFloat(); - mat4[0][2] = object->property("r2c0")->toVariant().toFloat(); - mat4[0][3] = object->property("r3c0")->toVariant().toFloat(); - mat4[1][0] = object->property("r0c1")->toVariant().toFloat(); - mat4[1][1] = object->property("r1c1")->toVariant().toFloat(); - mat4[1][2] = object->property("r2c1")->toVariant().toFloat(); - mat4[1][3] = object->property("r3c1")->toVariant().toFloat(); - mat4[2][0] = object->property("r0c2")->toVariant().toFloat(); - mat4[2][1] = object->property("r1c2")->toVariant().toFloat(); - mat4[2][2] = object->property("r2c2")->toVariant().toFloat(); - mat4[2][3] = object->property("r3c2")->toVariant().toFloat(); - mat4[3][0] = object->property("r0c3")->toVariant().toFloat(); - mat4[3][1] = object->property("r1c3")->toVariant().toFloat(); - mat4[3][2] = object->property("r2c3")->toVariant().toFloat(); - mat4[3][3] = object->property("r3c3")->toVariant().toFloat(); -} - -ScriptValuePointer qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector& vector) { - ScriptValuePointer array = engine->newArray(); +void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4) { + mat4[0][0] = object.property("r0c0").toVariant().toFloat(); + mat4[0][1] = object.property("r1c0").toVariant().toFloat(); + mat4[0][2] = object.property("r2c0").toVariant().toFloat(); + mat4[0][3] = object.property("r3c0").toVariant().toFloat(); + mat4[1][0] = object.property("r0c1").toVariant().toFloat(); + mat4[1][1] = object.property("r1c1").toVariant().toFloat(); + mat4[1][2] = object.property("r2c1").toVariant().toFloat(); + mat4[1][3] = object.property("r3c1").toVariant().toFloat(); + mat4[2][0] = object.property("r0c2").toVariant().toFloat(); + mat4[2][1] = object.property("r1c2").toVariant().toFloat(); + mat4[2][2] = object.property("r2c2").toVariant().toFloat(); + mat4[2][3] = object.property("r3c2").toVariant().toFloat(); + mat4[3][0] = object.property("r0c3").toVariant().toFloat(); + mat4[3][1] = object.property("r1c3").toVariant().toFloat(); + mat4[3][2] = object.property("r2c3").toVariant().toFloat(); + mat4[3][3] = object.property("r3c3").toVariant().toFloat(); +} + +ScriptValue qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { - array->setProperty(i, vec3ColorToScriptValue(engine, vector.at(i))); + array.setProperty(i, vec3ColorToScriptValue(engine, vector.at(i))); } return array; } -ScriptValuePointer qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector& vector) { - ScriptValuePointer array = engine->newArray(); +ScriptValue qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { - array->setProperty(i, vec3ToScriptValue(engine, vector.at(i))); + array.setProperty(i, vec3ToScriptValue(engine, vector.at(i))); } return array; } -QVector qVectorVec3FromScriptValue(const ScriptValuePointer& array) { +QVector qVectorVec3FromScriptValue(const ScriptValue& array) { QVector newVector; - int length = array->property("length")->toInteger(); + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { glm::vec3 newVec3 = glm::vec3(); - vec3FromScriptValue(array->property(i), newVec3); + vec3FromScriptValue(array.property(i), newVec3); newVector << newVec3; } return newVector; } -void qVectorVec3FromScriptValue(const ScriptValuePointer& array, QVector& vector) { - int length = array->property("length")->toInteger(); +void qVectorVec3FromScriptValue(const ScriptValue& array, QVector& vector) { + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { glm::vec3 newVec3 = glm::vec3(); - vec3FromScriptValue(array->property(i), newVec3); + vec3FromScriptValue(array.property(i), newVec3); vector << newVec3; } } -ScriptValuePointer quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) { - ScriptValuePointer obj = engine->newObject(); +ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) { + ScriptValue obj = engine->newObject(); if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) { // if quat contains a NaN don't try to convert it return obj; } - obj->setProperty("x", quat.x); - obj->setProperty("y", quat.y); - obj->setProperty("z", quat.z); - obj->setProperty("w", quat.w); + obj.setProperty("x", quat.x); + obj.setProperty("y", quat.y); + obj.setProperty("z", quat.z); + obj.setProperty("w", quat.w); return obj; } -void quatFromScriptValue(const ScriptValuePointer& object, glm::quat& quat) { - quat.x = object->property("x")->toVariant().toFloat(); - quat.y = object->property("y")->toVariant().toFloat(); - quat.z = object->property("z")->toVariant().toFloat(); - quat.w = object->property("w")->toVariant().toFloat(); +void quatFromScriptValue(const ScriptValue& object, glm::quat& quat) { + quat.x = object.property("x").toVariant().toFloat(); + quat.y = object.property("y").toVariant().toFloat(); + quat.z = object.property("z").toVariant().toFloat(); + quat.w = object.property("w").toVariant().toFloat(); // enforce normalized quaternion float length = glm::length(quat); @@ -442,181 +442,181 @@ void quatFromScriptValue(const ScriptValuePointer& object, glm::quat& quat) { } } -ScriptValuePointer qVectorQuatToScriptValue(ScriptEngine* engine, const QVector& vector) { - ScriptValuePointer array = engine->newArray(); +ScriptValue qVectorQuatToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { - array->setProperty(i, quatToScriptValue(engine, vector.at(i))); + array.setProperty(i, quatToScriptValue(engine, vector.at(i))); } return array; } -ScriptValuePointer qVectorBoolToScriptValue(ScriptEngine* engine, const QVector& vector) { - ScriptValuePointer array = engine->newArray(); +ScriptValue qVectorBoolToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { - array->setProperty(i, vector.at(i)); + array.setProperty(i, vector.at(i)); } return array; } -QVector qVectorFloatFromScriptValue(const ScriptValuePointer& array) { - if (!array->isArray()) { +QVector qVectorFloatFromScriptValue(const ScriptValue& array) { + if (!array.isArray()) { return QVector(); } QVector newVector; - int length = array->property("length")->toInteger(); + int length = array.property("length").toInteger(); newVector.reserve(length); for (int i = 0; i < length; i++) { - if (array->property(i)->isNumber()) { - newVector << array->property(i)->toNumber(); + if (array.property(i).isNumber()) { + newVector << array.property(i).toNumber(); } } return newVector; } -ScriptValuePointer qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector& vector) { - ScriptValuePointer array = engine->newArray(); +ScriptValue qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { - array->setProperty(i, quuidToScriptValue(engine, vector.at(i))); + array.setProperty(i, quuidToScriptValue(engine, vector.at(i))); } return array; } -void qVectorQUuidFromScriptValue(const ScriptValuePointer& array, QVector& vector) { - int length = array->property("length")->toInteger(); +void qVectorQUuidFromScriptValue(const ScriptValue& array, QVector& vector) { + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { - vector << array->property(i)->toVariant().toUuid(); + vector << array.property(i).toVariant().toUuid(); } } -QVector qVectorQUuidFromScriptValue(const ScriptValuePointer& array) { - if (!array->isArray()) { +QVector qVectorQUuidFromScriptValue(const ScriptValue& array) { + if (!array.isArray()) { return QVector(); } QVector newVector; - int length = array->property("length")->toInteger(); + int length = array.property("length").toInteger(); newVector.reserve(length); for (int i = 0; i < length; i++) { - QString uuidAsString = array->property(i)->toString(); + QString uuidAsString = array.property(i).toString(); QUuid fromString(uuidAsString); newVector << fromString; } return newVector; } -ScriptValuePointer qVectorFloatToScriptValue(ScriptEngine* engine, const QVector& vector) { - ScriptValuePointer array = engine->newArray(); +ScriptValue qVectorFloatToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { float num = vector.at(i); - array->setProperty(i, engine->newValue(num)); + array.setProperty(i, engine->newValue(num)); } return array; } -ScriptValuePointer qVectorIntToScriptValue(ScriptEngine* engine, const QVector& vector) { - ScriptValuePointer array = engine->newArray(); +ScriptValue qVectorIntToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { int num = vector.at(i); - array->setProperty(i, engine->newValue(num)); + array.setProperty(i, engine->newValue(num)); } return array; } -void qVectorFloatFromScriptValue(const ScriptValuePointer& array, QVector& vector) { - int length = array->property("length")->toInteger(); +void qVectorFloatFromScriptValue(const ScriptValue& array, QVector& vector) { + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { - vector << array->property(i)->toVariant().toFloat(); + vector << array.property(i).toVariant().toFloat(); } } -void qVectorIntFromScriptValue(const ScriptValuePointer& array, QVector& vector) { - int length = array->property("length")->toInteger(); +void qVectorIntFromScriptValue(const ScriptValue& array, QVector& vector) { + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { - vector << array->property(i)->toVariant().toInt(); + vector << array.property(i).toVariant().toInt(); } } -QVector qVectorQuatFromScriptValue(const ScriptValuePointer& array) { +QVector qVectorQuatFromScriptValue(const ScriptValue& array) { QVector newVector; - int length = array->property("length")->toInteger(); + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { glm::quat newQuat = glm::quat(); - quatFromScriptValue(array->property(i), newQuat); + quatFromScriptValue(array.property(i), newQuat); newVector << newQuat; } return newVector; } -void qVectorQuatFromScriptValue(const ScriptValuePointer& array, QVector& vector) { - int length = array->property("length")->toInteger(); +void qVectorQuatFromScriptValue(const ScriptValue& array, QVector& vector) { + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { glm::quat newQuat = glm::quat(); - quatFromScriptValue(array->property(i), newQuat); + quatFromScriptValue(array.property(i), newQuat); vector << newQuat; } } -QVector qVectorBoolFromScriptValue(const ScriptValuePointer& array) { +QVector qVectorBoolFromScriptValue(const ScriptValue& array) { QVector newVector; - int length = array->property("length")->toInteger(); + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { - newVector << array->property(i)->toBool(); + newVector << array.property(i).toBool(); } return newVector; } -void qVectorBoolFromScriptValue(const ScriptValuePointer& array, QVector& vector) { - int length = array->property("length")->toInteger(); +void qVectorBoolFromScriptValue(const ScriptValue& array, QVector& vector) { + int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { - vector << array->property(i)->toBool(); + vector << array.property(i).toBool(); } } -ScriptValuePointer qRectToScriptValue(ScriptEngine* engine, const QRect& rect) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("x", rect.x()); - obj->setProperty("y", rect.y()); - obj->setProperty("width", rect.width()); - obj->setProperty("height", rect.height()); +ScriptValue qRectToScriptValue(ScriptEngine* engine, const QRect& rect) { + ScriptValue obj = engine->newObject(); + obj.setProperty("x", rect.x()); + obj.setProperty("y", rect.y()); + obj.setProperty("width", rect.width()); + obj.setProperty("height", rect.height()); return obj; } -void qRectFromScriptValue(const ScriptValuePointer& object, QRect& rect) { - rect.setX(object->property("x")->toVariant().toInt()); - rect.setY(object->property("y")->toVariant().toInt()); - rect.setWidth(object->property("width")->toVariant().toInt()); - rect.setHeight(object->property("height")->toVariant().toInt()); +void qRectFromScriptValue(const ScriptValue& object, QRect& rect) { + rect.setX(object.property("x").toVariant().toInt()); + rect.setY(object.property("y").toVariant().toInt()); + rect.setWidth(object.property("width").toVariant().toInt()); + rect.setHeight(object.property("height").toVariant().toInt()); } -ScriptValuePointer qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("x", rect.x()); - obj->setProperty("y", rect.y()); - obj->setProperty("width", rect.width()); - obj->setProperty("height", rect.height()); +ScriptValue qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect) { + ScriptValue obj = engine->newObject(); + obj.setProperty("x", rect.x()); + obj.setProperty("y", rect.y()); + obj.setProperty("width", rect.width()); + obj.setProperty("height", rect.height()); return obj; } -void qRectFFromScriptValue(const ScriptValuePointer& object, QRectF& rect) { - rect.setX(object->property("x")->toVariant().toFloat()); - rect.setY(object->property("y")->toVariant().toFloat()); - rect.setWidth(object->property("width")->toVariant().toFloat()); - rect.setHeight(object->property("height")->toVariant().toFloat()); +void qRectFFromScriptValue(const ScriptValue& object, QRectF& rect) { + rect.setX(object.property("x").toVariant().toFloat()); + rect.setY(object.property("y").toVariant().toFloat()); + rect.setWidth(object.property("width").toVariant().toFloat()); + rect.setHeight(object.property("height").toVariant().toFloat()); } -ScriptValuePointer qColorToScriptValue(ScriptEngine* engine, const QColor& color) { - ScriptValuePointer object = engine->newObject(); - object->setProperty("red", color.red()); - object->setProperty("green", color.green()); - object->setProperty("blue", color.blue()); - object->setProperty("alpha", color.alpha()); +ScriptValue qColorToScriptValue(ScriptEngine* engine, const QColor& color) { + ScriptValue object = engine->newObject(); + object.setProperty("red", color.red()); + object.setProperty("green", color.green()); + object.setProperty("blue", color.blue()); + object.setProperty("alpha", color.alpha()); return object; } @@ -629,78 +629,78 @@ ScriptValuePointer qColorToScriptValue(ScriptEngine* engine, const QColor& color * @property {number} z - Z coordinate of the brn corner of the cube. * @property {number} scale - The dimensions of each side of the cube. */ -ScriptValuePointer aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube) { - ScriptValuePointer obj = engine->newObject(); +ScriptValue aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube) { + ScriptValue obj = engine->newObject(); const glm::vec3& corner = aaCube.getCorner(); - obj->setProperty("x", corner.x); - obj->setProperty("y", corner.y); - obj->setProperty("z", corner.z); - obj->setProperty("scale", aaCube.getScale()); + obj.setProperty("x", corner.x); + obj.setProperty("y", corner.y); + obj.setProperty("z", corner.z); + obj.setProperty("scale", aaCube.getScale()); return obj; } -void aaCubeFromScriptValue(const ScriptValuePointer& object, AACube& aaCube) { +void aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube) { glm::vec3 corner; - corner.x = object->property("x")->toVariant().toFloat(); - corner.y = object->property("y")->toVariant().toFloat(); - corner.z = object->property("z")->toVariant().toFloat(); - float scale = object->property("scale")->toVariant().toFloat(); + corner.x = object.property("x").toVariant().toFloat(); + corner.y = object.property("y").toVariant().toFloat(); + corner.z = object.property("z").toVariant().toFloat(); + float scale = object.property("scale").toVariant().toFloat(); aaCube.setBox(corner, scale); } -void qColorFromScriptValue(const ScriptValuePointer& object, QColor& color) { - if (object->isNumber()) { - color.setRgb(object->toUInt32()); +void qColorFromScriptValue(const ScriptValue& object, QColor& color) { + if (object.isNumber()) { + color.setRgb(object.toUInt32()); - } else if (object->isString()) { - color.setNamedColor(object->toString()); + } else if (object.isString()) { + color.setNamedColor(object.toString()); } else { - ScriptValuePointer alphaValue = object->property("alpha"); - color.setRgb(object->property("red")->toInt32(), object->property("green")->toInt32(), object->property("blue")->toInt32(), - alphaValue->isNumber() ? alphaValue->toInt32() : 255); + ScriptValue alphaValue = object.property("alpha"); + color.setRgb(object.property("red").toInt32(), object.property("green").toInt32(), object.property("blue").toInt32(), + alphaValue.isNumber() ? alphaValue.toInt32() : 255); } } -ScriptValuePointer qURLToScriptValue(ScriptEngine* engine, const QUrl& url) { +ScriptValue qURLToScriptValue(ScriptEngine* engine, const QUrl& url) { return engine->newValue(url.toString()); } -void qURLFromScriptValue(const ScriptValuePointer& object, QUrl& url) { - url = object->toString(); +void qURLFromScriptValue(const ScriptValue& object, QUrl& url) { + url = object.toString(); } -ScriptValuePointer pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay) { - ScriptValuePointer obj = engine->newObject(); - ScriptValuePointer origin = vec3ToScriptValue(engine, pickRay.origin); - obj->setProperty("origin", origin); - ScriptValuePointer direction = vec3ToScriptValue(engine, pickRay.direction); - obj->setProperty("direction", direction); +ScriptValue pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay) { + ScriptValue obj = engine->newObject(); + ScriptValue origin = vec3ToScriptValue(engine, pickRay.origin); + obj.setProperty("origin", origin); + ScriptValue direction = vec3ToScriptValue(engine, pickRay.direction); + obj.setProperty("direction", direction); return obj; } -void pickRayFromScriptValue(const ScriptValuePointer& object, PickRay& pickRay) { - ScriptValuePointer originValue = object->property("origin"); - if (originValue->isValid()) { - auto x = originValue->property("x"); - auto y = originValue->property("y"); - auto z = originValue->property("z"); - if (x->isValid() && y->isValid() && z->isValid()) { - pickRay.origin.x = x->toVariant().toFloat(); - pickRay.origin.y = y->toVariant().toFloat(); - pickRay.origin.z = z->toVariant().toFloat(); +void pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay) { + ScriptValue originValue = object.property("origin"); + if (originValue.isValid()) { + auto x = originValue.property("x"); + auto y = originValue.property("y"); + auto z = originValue.property("z"); + if (x.isValid() && y.isValid() && z.isValid()) { + pickRay.origin.x = x.toVariant().toFloat(); + pickRay.origin.y = y.toVariant().toFloat(); + pickRay.origin.z = z.toVariant().toFloat(); } } - ScriptValuePointer directionValue = object->property("direction"); - if (directionValue->isValid()) { - auto x = directionValue->property("x"); - auto y = directionValue->property("y"); - auto z = directionValue->property("z"); - if (x->isValid() && y->isValid() && z->isValid()) { - pickRay.direction.x = x->toVariant().toFloat(); - pickRay.direction.y = y->toVariant().toFloat(); - pickRay.direction.z = z->toVariant().toFloat(); + ScriptValue directionValue = object.property("direction"); + if (directionValue.isValid()) { + auto x = directionValue.property("x"); + auto y = directionValue.property("y"); + auto z = directionValue.property("z"); + if (x.isValid() && y.isValid() && z.isValid()) { + pickRay.direction.x = x.toVariant().toFloat(); + pickRay.direction.y = y.toVariant().toFloat(); + pickRay.direction.z = z.toVariant().toFloat(); } } } @@ -715,35 +715,35 @@ void pickRayFromScriptValue(const ScriptValuePointer& object, PickRay& pickRay) * @property {Vec3} contactPoint - The point of contact. * @property {Vec3} velocityChange - The change in relative velocity of the two items, in m/s. */ -ScriptValuePointer collisionToScriptValue(ScriptEngine* engine, const Collision& collision) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("type", collision.type); - obj->setProperty("idA", quuidToScriptValue(engine, collision.idA)); - obj->setProperty("idB", quuidToScriptValue(engine, collision.idB)); - obj->setProperty("penetration", vec3ToScriptValue(engine, collision.penetration)); - obj->setProperty("contactPoint", vec3ToScriptValue(engine, collision.contactPoint)); - obj->setProperty("velocityChange", vec3ToScriptValue(engine, collision.velocityChange)); +ScriptValue collisionToScriptValue(ScriptEngine* engine, const Collision& collision) { + ScriptValue obj = engine->newObject(); + obj.setProperty("type", collision.type); + obj.setProperty("idA", quuidToScriptValue(engine, collision.idA)); + obj.setProperty("idB", quuidToScriptValue(engine, collision.idB)); + obj.setProperty("penetration", vec3ToScriptValue(engine, collision.penetration)); + obj.setProperty("contactPoint", vec3ToScriptValue(engine, collision.contactPoint)); + obj.setProperty("velocityChange", vec3ToScriptValue(engine, collision.velocityChange)); return obj; } -void collisionFromScriptValue(const ScriptValuePointer& object, Collision& collision) { +void collisionFromScriptValue(const ScriptValue& object, Collision& collision) { // TODO: implement this when we know what it means to accept collision events from JS } -ScriptValuePointer quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid) { +ScriptValue quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid) { if (uuid.isNull()) { return engine->nullValue(); } - ScriptValuePointer obj(engine->newValue(uuid.toString())); + ScriptValue obj(engine->newValue(uuid.toString())); return obj; } -void quuidFromScriptValue(const ScriptValuePointer& object, QUuid& uuid) { +void quuidFromScriptValue(const ScriptValue& object, QUuid& uuid) { if (object.isNull()) { uuid = QUuid(); return; } - QString uuidAsString = object->toVariant().toString(); + QString uuidAsString = object.toVariant().toString(); QUuid fromString(uuidAsString); uuid = fromString; } @@ -754,16 +754,16 @@ void quuidFromScriptValue(const ScriptValuePointer& object, QUuid& uuid) { * @property {number} height - The height value. * @property {number} width - The width value. */ -ScriptValuePointer qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("width", qSizeF.width()); - obj->setProperty("height", qSizeF.height()); +ScriptValue qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF) { + ScriptValue obj = engine->newObject(); + obj.setProperty("width", qSizeF.width()); + obj.setProperty("height", qSizeF.height()); return obj; } -void qSizeFFromScriptValue(const ScriptValuePointer& object, QSizeF& qSizeF) { - qSizeF.setWidth(object->property("width")->toVariant().toFloat()); - qSizeF.setHeight(object->property("height")->toVariant().toFloat()); +void qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF) { + qSizeF.setWidth(object.property("width").toVariant().toFloat()); + qSizeF.setHeight(object.property("height").toVariant().toFloat()); } /*@jsdoc @@ -785,47 +785,47 @@ void qSizeFFromScriptValue(const ScriptValuePointer& object, QSizeF& qSizeF) { * @property {boolean} startAutomatically - Not used. * @property {boolean} allowTranslation - Not used. */ -ScriptValuePointer animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& details) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("role", details.role); - obj->setProperty("url", details.url.toString()); - obj->setProperty("fps", details.fps); - obj->setProperty("priority", details.priority); - obj->setProperty("loop", details.loop); - obj->setProperty("hold", details.hold); - obj->setProperty("startAutomatically", details.startAutomatically); - obj->setProperty("firstFrame", details.firstFrame); - obj->setProperty("lastFrame", details.lastFrame); - obj->setProperty("running", details.running); - obj->setProperty("currentFrame", details.currentFrame); - obj->setProperty("allowTranslation", details.allowTranslation); +ScriptValue animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& details) { + ScriptValue obj = engine->newObject(); + obj.setProperty("role", details.role); + obj.setProperty("url", details.url.toString()); + obj.setProperty("fps", details.fps); + obj.setProperty("priority", details.priority); + obj.setProperty("loop", details.loop); + obj.setProperty("hold", details.hold); + obj.setProperty("startAutomatically", details.startAutomatically); + obj.setProperty("firstFrame", details.firstFrame); + obj.setProperty("lastFrame", details.lastFrame); + obj.setProperty("running", details.running); + obj.setProperty("currentFrame", details.currentFrame); + obj.setProperty("allowTranslation", details.allowTranslation); return obj; } -void animationDetailsFromScriptValue(const ScriptValuePointer& object, AnimationDetails& details) { +void animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& details) { // nothing for now... } -ScriptValuePointer meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in) { +ScriptValue meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in) { return engine->newQObject(in, ScriptEngine::QtOwnership); } -void meshFromScriptValue(const ScriptValuePointer& value, MeshProxy*& out) { - out = qobject_cast(value->toQObject()); +void meshFromScriptValue(const ScriptValue& value, MeshProxy*& out) { + out = qobject_cast(value.toQObject()); } -ScriptValuePointer meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in) { +ScriptValue meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in) { // ScriptValueList result; - ScriptValuePointer result = engine->newArray(); + ScriptValue result = engine->newArray(); int i = 0; - foreach (MeshProxy* const meshProxy, in) { result->setProperty(i++, meshToScriptValue(engine, meshProxy)); } + foreach (MeshProxy* const meshProxy, in) { result.setProperty(i++, meshToScriptValue(engine, meshProxy)); } return result; } -void meshesFromScriptValue(const ScriptValuePointer& value, MeshProxyList& out) { - ScriptValueIteratorPointer itr(value->newIterator()); +void meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out) { + ScriptValueIteratorPointer itr(value.newIterator()); - qDebug() << "in meshesFromScriptValue, value.length =" << value->property("length")->toInt32(); + qDebug() << "in meshesFromScriptValue, value.length =" << value.property("length").toInt32(); while (itr->hasNext()) { itr->next(); @@ -843,67 +843,67 @@ void meshesFromScriptValue(const ScriptValuePointer& value, MeshProxyList& out) * @typedef {object} MeshFace * @property {number[]} vertices - The indexes of the three vertices that make up the face. */ -ScriptValuePointer meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices)); +ScriptValue meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace) { + ScriptValue obj = engine->newObject(); + obj.setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices)); return obj; } -void meshFaceFromScriptValue(const ScriptValuePointer& object, MeshFace& meshFaceResult) { - qVectorIntFromScriptValue(object->property("vertices"), meshFaceResult.vertexIndices); +void meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult) { + qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices); } -ScriptValuePointer qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& vector) { - ScriptValuePointer array = engine->newArray(); +ScriptValue qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { - array->setProperty(i, meshFaceToScriptValue(engine, vector.at(i))); + array.setProperty(i, meshFaceToScriptValue(engine, vector.at(i))); } return array; } -void qVectorMeshFaceFromScriptValue(const ScriptValuePointer& array, QVector& result) { - int length = array->property("length")->toInteger(); +void qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector& result) { + int length = array.property("length").toInteger(); result.clear(); for (int i = 0; i < length; i++) { MeshFace meshFace = MeshFace(); - meshFaceFromScriptValue(array->property(i), meshFace); + meshFaceFromScriptValue(array.property(i), meshFace); result << meshFace; } } -ScriptValuePointer stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode) { +ScriptValue stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode) { return engine->newValue((int)stencilMode); } -void stencilMaskModeFromScriptValue(const ScriptValuePointer& object, StencilMaskMode& stencilMode) { - stencilMode = StencilMaskMode(object->toVariant().toInt()); +void stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode) { + stencilMode = StencilMaskMode(object.toVariant().toInt()); } -void promiseFromScriptValue(const ScriptValuePointer& object, std::shared_ptr& promise) { +void promiseFromScriptValue(const ScriptValue& object, std::shared_ptr& promise) { Q_ASSERT(false); } -ScriptValuePointer promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise) { +ScriptValue promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise) { return engine->newQObject(promise.get()); } -ScriptValuePointer EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& id) { +ScriptValue EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& id) { return quuidToScriptValue(engine, id); } -void EntityItemIDfromScriptValue(const ScriptValuePointer &object, EntityItemID& id) { +void EntityItemIDfromScriptValue(const ScriptValue &object, EntityItemID& id) { quuidFromScriptValue(object, id); } -QVector qVectorEntityItemIDFromScriptValue(const ScriptValuePointer& array) { - if (!array->isArray()) { +QVector qVectorEntityItemIDFromScriptValue(const ScriptValue& array) { + if (!array.isArray()) { return QVector(); } QVector newVector; - int length = array->property("length")->toInteger(); + int length = array.property("length").toInteger(); newVector.reserve(length); for (int i = 0; i < length; i++) { - QString uuidAsString = array->property(i)->toString(); + QString uuidAsString = array.property(i).toString(); EntityItemID fromString(uuidAsString); newVector << fromString; } diff --git a/libraries/script-engine/src/ScriptValueUtils.h b/libraries/script-engine/src/ScriptValueUtils.h index 8d0919ee5b2..6b478ea36f3 100644 --- a/libraries/script-engine/src/ScriptValueUtils.h +++ b/libraries/script-engine/src/ScriptValueUtils.h @@ -24,7 +24,7 @@ #include "ScriptValue.h" -bool isListOfStrings(const ScriptValuePointer& value); +bool isListOfStrings(const ScriptValue& value); void registerMetaTypes(ScriptEngine* engine); @@ -51,8 +51,8 @@ void registerMetaTypes(ScriptEngine* engine); * @property {number} r2c3 - Row 2, column 3 value. * @property {number} r3c3 - Row 3, column 3 value. */ -ScriptValuePointer mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4); -void mat4FromScriptValue(const ScriptValuePointer& object, glm::mat4& mat4); +ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4); +void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4); /*@jsdoc * A 2-dimensional vector. @@ -68,8 +68,8 @@ void mat4FromScriptValue(const ScriptValuePointer& object, glm::mat4& mat4); * var color = Entities.getEntityProperties().materialMappingPos; // { x: 0.7, y: 0.7 } * color.v = 0.8; // { x: 0.7, y: 0.8 } */ -ScriptValuePointer vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2); -void vec2FromScriptValue(const ScriptValuePointer& object, glm::vec2& vec2); +ScriptValue vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2); +void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2); /*@jsdoc * A 3-dimensional vector. See also the {@link Vec3(0)|Vec3} object. @@ -91,9 +91,9 @@ void vec2FromScriptValue(const ScriptValuePointer& object, glm::vec2& vec2); * Entities.editEntity(, { position: "red"}); // { x: 255, y: 0, z: 0 } * Entities.editEntity(, { position: "#00FF00"}); // { x: 0, y: 255, z: 0 } */ -ScriptValuePointer vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3); -ScriptValuePointer vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3); -void vec3FromScriptValue(const ScriptValuePointer& object, glm::vec3& vec3); +ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3); +ScriptValue vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3); +void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3); /*@jsdoc * A color vector. See also the {@link Vec3(0)|Vec3} object. @@ -133,9 +133,9 @@ void vec3FromScriptValue(const ScriptValuePointer& object, glm::vec3& vec3); * Entities.editEntity(, { color: "red"}); // { red: 255, green: 0, blue: 0 } * Entities.editEntity(, { color: "#00FF00"}); // { red: 0, green: 255, blue: 0 } */ -ScriptValuePointer u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3); -ScriptValuePointer u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3); -void u8vec3FromScriptValue(const ScriptValuePointer& object, glm::u8vec3& vec3); +ScriptValue u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3); +ScriptValue u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3); +void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3); /*@jsdoc * A 4-dimensional vector. @@ -146,12 +146,12 @@ void u8vec3FromScriptValue(const ScriptValuePointer& object, glm::u8vec3& vec3); * @property {number} z - Z-coordinate of the vector. * @property {number} w - W-coordinate of the vector. */ -ScriptValuePointer vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4); -void vec4FromScriptValue(const ScriptValuePointer& object, glm::vec4& vec4); +ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4); +void vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4); // Quaternions -ScriptValuePointer quatToScriptValue(ScriptEngine* engine, const glm::quat& quat); -void quatFromScriptValue(const ScriptValuePointer& object, glm::quat& quat); +ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat); +void quatFromScriptValue(const ScriptValue& object, glm::quat& quat); /*@jsdoc * Defines a rectangular portion of an image or screen, or similar. @@ -162,64 +162,64 @@ void quatFromScriptValue(const ScriptValuePointer& object, glm::quat& quat); * @property {number} height - Height of the rectangle. */ class QRect; -ScriptValuePointer qRectToScriptValue(ScriptEngine* engine, const QRect& rect); -void qRectFromScriptValue(const ScriptValuePointer& object, QRect& rect); +ScriptValue qRectToScriptValue(ScriptEngine* engine, const QRect& rect); +void qRectFromScriptValue(const ScriptValue& object, QRect& rect); class QRectF; -ScriptValuePointer qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect); -void qRectFFromScriptValue(const ScriptValuePointer& object, QRectF& rect); +ScriptValue qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect); +void qRectFFromScriptValue(const ScriptValue& object, QRectF& rect); // QColor class QColor; -ScriptValuePointer qColorToScriptValue(ScriptEngine* engine, const QColor& color); -void qColorFromScriptValue(const ScriptValuePointer& object, QColor& color); +ScriptValue qColorToScriptValue(ScriptEngine* engine, const QColor& color); +void qColorFromScriptValue(const ScriptValue& object, QColor& color); class QUrl; -ScriptValuePointer qURLToScriptValue(ScriptEngine* engine, const QUrl& url); -void qURLFromScriptValue(const ScriptValuePointer& object, QUrl& url); +ScriptValue qURLToScriptValue(ScriptEngine* engine, const QUrl& url); +void qURLFromScriptValue(const ScriptValue& object, QUrl& url); // vector Q_DECLARE_METATYPE(QVector) -ScriptValuePointer qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector& vector); -ScriptValuePointer qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorVec3FromScriptValue(const ScriptValuePointer& array, QVector& vector); -QVector qVectorVec3FromScriptValue(const ScriptValuePointer& array); +ScriptValue qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector& vector); +ScriptValue qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorVec3FromScriptValue(const ScriptValue& array, QVector& vector); +QVector qVectorVec3FromScriptValue(const ScriptValue& array); // vector Q_DECLARE_METATYPE(QVector) -ScriptValuePointer qVectorQuatToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorQuatFromScriptValue(const ScriptValuePointer& array, QVector& vector); -QVector qVectorQuatFromScriptValue(const ScriptValuePointer& array); +ScriptValue qVectorQuatToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorQuatFromScriptValue(const ScriptValue& array, QVector& vector); +QVector qVectorQuatFromScriptValue(const ScriptValue& array); // vector -ScriptValuePointer qVectorBoolToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorBoolFromScriptValue(const ScriptValuePointer& array, QVector& vector); -QVector qVectorBoolFromScriptValue(const ScriptValuePointer& array); +ScriptValue qVectorBoolToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorBoolFromScriptValue(const ScriptValue& array, QVector& vector); +QVector qVectorBoolFromScriptValue(const ScriptValue& array); // vector -ScriptValuePointer qVectorFloatToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorFloatFromScriptValue(const ScriptValuePointer& array, QVector& vector); -QVector qVectorFloatFromScriptValue(const ScriptValuePointer& array); +ScriptValue qVectorFloatToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorFloatFromScriptValue(const ScriptValue& array, QVector& vector); +QVector qVectorFloatFromScriptValue(const ScriptValue& array); // vector -ScriptValuePointer qVectorIntToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorIntFromScriptValue(const ScriptValuePointer& array, QVector& vector); +ScriptValue qVectorIntToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorIntFromScriptValue(const ScriptValue& array, QVector& vector); -ScriptValuePointer qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorQUuidFromScriptValue(const ScriptValuePointer& array, QVector& vector); -QVector qVectorQUuidFromScriptValue(const ScriptValuePointer& array); +ScriptValue qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorQUuidFromScriptValue(const ScriptValue& array, QVector& vector); +QVector qVectorQUuidFromScriptValue(const ScriptValue& array); class AACube; -ScriptValuePointer aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube); -void aaCubeFromScriptValue(const ScriptValuePointer& object, AACube& aaCube); +ScriptValue aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube); +void aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube); class PickRay; -ScriptValuePointer pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay); -void pickRayFromScriptValue(const ScriptValuePointer& object, PickRay& pickRay); +ScriptValue pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay); +void pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay); class Collision; -ScriptValuePointer collisionToScriptValue(ScriptEngine* engine, const Collision& collision); -void collisionFromScriptValue(const ScriptValuePointer& object, Collision& collision); +ScriptValue collisionToScriptValue(ScriptEngine* engine, const Collision& collision); +void collisionFromScriptValue(const ScriptValue& object, Collision& collision); /*@jsdoc * UUIDs (Universally Unique IDentifiers) are used to uniquely identify entities, avatars, and the like. They are represented @@ -228,44 +228,44 @@ void collisionFromScriptValue(const ScriptValuePointer& object, Collision& colli * @typedef {string} Uuid */ //Q_DECLARE_METATYPE(QUuid) // don't need to do this for QUuid since it's already a meta type -ScriptValuePointer quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid); -void quuidFromScriptValue(const ScriptValuePointer& object, QUuid& uuid); +ScriptValue quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid); +void quuidFromScriptValue(const ScriptValue& object, QUuid& uuid); //Q_DECLARE_METATYPE(QSizeF) // Don't need to to this becase it's arleady a meta type class QSizeF; -ScriptValuePointer qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF); -void qSizeFFromScriptValue(const ScriptValuePointer& object, QSizeF& qSizeF); +ScriptValue qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF); +void qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF); class AnimationDetails; -ScriptValuePointer animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& event); -void animationDetailsFromScriptValue(const ScriptValuePointer& object, AnimationDetails& event); +ScriptValue animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& event); +void animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& event); class MeshProxy; -ScriptValuePointer meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in); -void meshFromScriptValue(const ScriptValuePointer& value, MeshProxy*& out); +ScriptValue meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in); +void meshFromScriptValue(const ScriptValue& value, MeshProxy*& out); class MeshProxyList; -ScriptValuePointer meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in); -void meshesFromScriptValue(const ScriptValuePointer& value, MeshProxyList& out); +ScriptValue meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in); +void meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out); class MeshFace; -ScriptValuePointer meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace); -void meshFaceFromScriptValue(const ScriptValuePointer& object, MeshFace& meshFaceResult); -ScriptValuePointer qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorMeshFaceFromScriptValue(const ScriptValuePointer& array, QVector& result); +ScriptValue meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace); +void meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult); +ScriptValue qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& vector); +void qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector& result); enum class StencilMaskMode; -ScriptValuePointer stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode); -void stencilMaskModeFromScriptValue(const ScriptValuePointer& object, StencilMaskMode& stencilMode); +ScriptValue stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode); +void stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode); class MiniPromise; -void promiseFromScriptValue(const ScriptValuePointer& object, std::shared_ptr& promise); -ScriptValuePointer promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise); +void promiseFromScriptValue(const ScriptValue& object, std::shared_ptr& promise); +ScriptValue promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise); class EntityItemID; -ScriptValuePointer EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& properties); -void EntityItemIDfromScriptValue(const ScriptValuePointer& object, EntityItemID& properties); -QVector qVectorEntityItemIDFromScriptValue(const ScriptValuePointer& array); +ScriptValue EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& properties); +void EntityItemIDfromScriptValue(const ScriptValue& object, EntityItemID& properties); +QVector qVectorEntityItemIDFromScriptValue(const ScriptValue& array); #endif // #define hifi_ScriptValueUtils_h diff --git a/libraries/script-engine/src/Scriptable.h b/libraries/script-engine/src/Scriptable.h index d9e8403e27f..39d5974168a 100644 --- a/libraries/script-engine/src/Scriptable.h +++ b/libraries/script-engine/src/Scriptable.h @@ -18,20 +18,19 @@ #include #include "ScriptContext.h" +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; using ScriptEnginePointer = QSharedPointer; -using ScriptValuePointer = QSharedPointer; /// [ScriptInterface] Provides an engine-independent interface for QScriptable class Scriptable { public: static inline ScriptEnginePointer engine(); static ScriptContext* context(); - static inline ScriptValuePointer thisObject(); + static inline ScriptValue thisObject(); static inline int argumentCount(); - static inline ScriptValuePointer argument(int index); + static inline ScriptValue argument(int index); static void setContext(ScriptContext* context); }; @@ -42,9 +41,9 @@ ScriptEnginePointer Scriptable::engine() { return scriptContext->engine(); } -ScriptValuePointer Scriptable::thisObject() { +ScriptValue Scriptable::thisObject() { ScriptContext* scriptContext = context(); - if (!scriptContext) return nullptr; + if (!scriptContext) return ScriptValue(); return scriptContext->thisObject(); } @@ -54,9 +53,9 @@ int Scriptable::argumentCount() { return scriptContext->argumentCount(); } -ScriptValuePointer Scriptable::argument(int index) { +ScriptValue Scriptable::argument(int index) { ScriptContext* scriptContext = context(); - if (!scriptContext) return ScriptValuePointer(); + if (!scriptContext) return ScriptValue(); return scriptContext->argument(index); } diff --git a/libraries/script-engine/src/ScriptsModel.h b/libraries/script-engine/src/ScriptsModel.h index 9526a18bbae..74289420914 100644 --- a/libraries/script-engine/src/ScriptsModel.h +++ b/libraries/script-engine/src/ScriptsModel.h @@ -19,11 +19,8 @@ #include #include #include -#include class TreeNodeFolder; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; enum ScriptOrigin { SCRIPT_ORIGIN_LOCAL, @@ -147,10 +144,10 @@ class ScriptsModel : public QAbstractItemModel { // No JSDoc because the particulars of the parent class is provided in the @class description. int columnCount(const QModelIndex& parent = QModelIndex()) const override; - // Not exposed in the API because no conversion between TreeNodeBase and ScriptValuePointer is provided. + // Not exposed in the API because no conversion between TreeNodeBase and ScriptValue is provided. TreeNodeBase* getTreeNodeFromIndex(const QModelIndex& index) const; - // Not exposed in the API because no conversion between TreeNodeBase and ScriptValuePointer is provided. + // Not exposed in the API because no conversion between TreeNodeBase and ScriptValue is provided. QList getFolderNodes(TreeNodeFolder* parent) const; enum Role { diff --git a/libraries/script-engine/src/SpatialEvent.cpp b/libraries/script-engine/src/SpatialEvent.cpp index 0c5d96db45b..bada11b66e7 100644 --- a/libraries/script-engine/src/SpatialEvent.cpp +++ b/libraries/script-engine/src/SpatialEvent.cpp @@ -33,17 +33,17 @@ SpatialEvent::SpatialEvent(const SpatialEvent& event) { } -ScriptValuePointer SpatialEvent::toScriptValue(ScriptEngine* engine, const SpatialEvent& event) { - ScriptValuePointer obj = engine->newObject(); +ScriptValue SpatialEvent::toScriptValue(ScriptEngine* engine, const SpatialEvent& event) { + ScriptValue obj = engine->newObject(); - obj->setProperty("locTranslation", vec3ToScriptValue(engine, event.locTranslation) ); - obj->setProperty("locRotation", quatToScriptValue(engine, event.locRotation) ); - obj->setProperty("absTranslation", vec3ToScriptValue(engine, event.absTranslation)); - obj->setProperty("absRotation", quatToScriptValue(engine, event.absRotation)); + obj.setProperty("locTranslation", vec3ToScriptValue(engine, event.locTranslation) ); + obj.setProperty("locRotation", quatToScriptValue(engine, event.locRotation) ); + obj.setProperty("absTranslation", vec3ToScriptValue(engine, event.absTranslation)); + obj.setProperty("absRotation", quatToScriptValue(engine, event.absRotation)); return obj; } -void SpatialEvent::fromScriptValue(const ScriptValuePointer& object,SpatialEvent& event) { +void SpatialEvent::fromScriptValue(const ScriptValue& object,SpatialEvent& event) { // nothing for now... } diff --git a/libraries/script-engine/src/SpatialEvent.h b/libraries/script-engine/src/SpatialEvent.h index 197d5a6a98d..be7e5d33202 100644 --- a/libraries/script-engine/src/SpatialEvent.h +++ b/libraries/script-engine/src/SpatialEvent.h @@ -17,11 +17,10 @@ #include #include -#include + +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// [unused] Represents a spatial event to the scripting engine class SpatialEvent { @@ -29,8 +28,8 @@ class SpatialEvent { SpatialEvent(); SpatialEvent(const SpatialEvent& other); - static ScriptValuePointer toScriptValue(ScriptEngine* engine, const SpatialEvent& event); - static void fromScriptValue(const ScriptValuePointer& object, SpatialEvent& event); + static ScriptValue toScriptValue(ScriptEngine* engine, const SpatialEvent& event); + static void fromScriptValue(const ScriptValue& object, SpatialEvent& event); glm::vec3 locTranslation; glm::quat locRotation; diff --git a/libraries/script-engine/src/TouchEvent.cpp b/libraries/script-engine/src/TouchEvent.cpp index e85b773ef60..593eb326fc7 100644 --- a/libraries/script-engine/src/TouchEvent.cpp +++ b/libraries/script-engine/src/TouchEvent.cpp @@ -204,47 +204,47 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) { * print(JSON.stringify(event)); * }); */ -ScriptValuePointer TouchEvent::toScriptValue(ScriptEngine* engine, const TouchEvent& event) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("x", event.x); - obj->setProperty("y", event.y); - obj->setProperty("isPressed", event.isPressed); - obj->setProperty("isMoved", event.isMoved); - obj->setProperty("isStationary", event.isStationary); - obj->setProperty("isReleased", event.isReleased); - obj->setProperty("isShifted", event.isShifted); - obj->setProperty("isMeta", event.isMeta); - obj->setProperty("isControl", event.isControl); - obj->setProperty("isAlt", event.isAlt); - obj->setProperty("touchPoints", event.touchPoints); - - ScriptValuePointer pointsObj = engine->newArray(); +ScriptValue TouchEvent::toScriptValue(ScriptEngine* engine, const TouchEvent& event) { + ScriptValue obj = engine->newObject(); + obj.setProperty("x", event.x); + obj.setProperty("y", event.y); + obj.setProperty("isPressed", event.isPressed); + obj.setProperty("isMoved", event.isMoved); + obj.setProperty("isStationary", event.isStationary); + obj.setProperty("isReleased", event.isReleased); + obj.setProperty("isShifted", event.isShifted); + obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); + obj.setProperty("touchPoints", event.touchPoints); + + ScriptValue pointsObj = engine->newArray(); int index = 0; foreach (glm::vec2 point, event.points) { - ScriptValuePointer thisPoint = vec2ToScriptValue(engine, point); - pointsObj->setProperty(index, thisPoint); + ScriptValue thisPoint = vec2ToScriptValue(engine, point); + pointsObj.setProperty(index, thisPoint); index++; } - obj->setProperty("points", pointsObj); - obj->setProperty("radius", event.radius); - obj->setProperty("isPinching", event.isPinching); - obj->setProperty("isPinchOpening", event.isPinchOpening); - - obj->setProperty("angle", event.angle); - obj->setProperty("deltaAngle", event.deltaAngle); - ScriptValuePointer anglesObj = engine->newArray(); + obj.setProperty("points", pointsObj); + obj.setProperty("radius", event.radius); + obj.setProperty("isPinching", event.isPinching); + obj.setProperty("isPinchOpening", event.isPinchOpening); + + obj.setProperty("angle", event.angle); + obj.setProperty("deltaAngle", event.deltaAngle); + ScriptValue anglesObj = engine->newArray(); index = 0; foreach (float angle, event.angles) { - anglesObj->setProperty(index, angle); + anglesObj.setProperty(index, angle); index++; } - obj->setProperty("angles", anglesObj); + obj.setProperty("angles", anglesObj); - obj->setProperty("isRotating", event.isRotating); - obj->setProperty("rotating", event.rotating); + obj.setProperty("isRotating", event.isRotating); + obj.setProperty("rotating", event.rotating); return obj; } -void TouchEvent::fromScriptValue(const ScriptValuePointer& object, TouchEvent& event) { +void TouchEvent::fromScriptValue(const ScriptValue& object, TouchEvent& event) { // nothing for now... } diff --git a/libraries/script-engine/src/TouchEvent.h b/libraries/script-engine/src/TouchEvent.h index 2aa49be0536..3a0861b4e7f 100644 --- a/libraries/script-engine/src/TouchEvent.h +++ b/libraries/script-engine/src/TouchEvent.h @@ -19,11 +19,10 @@ #include #include -#include + +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// Represents a display or device event to the scripting engine. Exposed as TouchEvent class TouchEvent { @@ -32,8 +31,8 @@ class TouchEvent { TouchEvent(const QTouchEvent& event); TouchEvent(const QTouchEvent& event, const TouchEvent& other); - static ScriptValuePointer toScriptValue(ScriptEngine* engine, const TouchEvent& event); - static void fromScriptValue(const ScriptValuePointer& object, TouchEvent& event); + static ScriptValue toScriptValue(ScriptEngine* engine, const TouchEvent& event); + static void fromScriptValue(const ScriptValue& object, TouchEvent& event); float x; float y; diff --git a/libraries/script-engine/src/VariantMapToScriptValue.cpp b/libraries/script-engine/src/VariantMapToScriptValue.cpp index 1b206e410d0..a1a50ed207d 100644 --- a/libraries/script-engine/src/VariantMapToScriptValue.cpp +++ b/libraries/script-engine/src/VariantMapToScriptValue.cpp @@ -15,7 +15,7 @@ #include "SharedLogging.h" -ScriptValuePointer variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEngine) { +ScriptValue variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEngine) { switch(qValue.type()) { case QVariant::Bool: return scriptEngine.newValue(qValue.toBool()); @@ -48,29 +48,29 @@ ScriptValuePointer variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEn break; } - return ScriptValuePointer(); + return ScriptValue(); } -ScriptValuePointer variantMapToScriptValue(QVariantMap& variantMap, ScriptEngine& scriptEngine) { - ScriptValuePointer scriptValue = scriptEngine.newObject(); +ScriptValue variantMapToScriptValue(QVariantMap& variantMap, ScriptEngine& scriptEngine) { + ScriptValue scriptValue = scriptEngine.newObject(); for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) { QString key = iter.key(); QVariant qValue = iter.value(); - scriptValue->setProperty(key, variantToScriptValue(qValue, scriptEngine)); + scriptValue.setProperty(key, variantToScriptValue(qValue, scriptEngine)); } return scriptValue; } -ScriptValuePointer variantListToScriptValue(QVariantList& variantList, ScriptEngine& scriptEngine) { +ScriptValue variantListToScriptValue(QVariantList& variantList, ScriptEngine& scriptEngine) { - ScriptValuePointer scriptValue = scriptEngine.newArray(); + ScriptValue scriptValue = scriptEngine.newArray(); for (int i = 0; i < variantList.size(); i++) { - scriptValue->setProperty(i, variantToScriptValue(variantList[i], scriptEngine)); + scriptValue.setProperty(i, variantToScriptValue(variantList[i], scriptEngine)); } return scriptValue; diff --git a/libraries/script-engine/src/VariantMapToScriptValue.h b/libraries/script-engine/src/VariantMapToScriptValue.h index 3093938d371..956f7c2f152 100644 --- a/libraries/script-engine/src/VariantMapToScriptValue.h +++ b/libraries/script-engine/src/VariantMapToScriptValue.h @@ -16,8 +16,8 @@ #include "ScriptValue.h" #include "ScriptEngine.h" -ScriptValuePointer variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEngine); -ScriptValuePointer variantMapToScriptValue(QVariantMap& variantMap, ScriptEngine& scriptEngine); -ScriptValuePointer variantListToScriptValue(QVariantList& variantList, ScriptEngine& scriptEngine); +ScriptValue variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEngine); +ScriptValue variantMapToScriptValue(QVariantMap& variantMap, ScriptEngine& scriptEngine); +ScriptValue variantListToScriptValue(QVariantList& variantList, ScriptEngine& scriptEngine); /// @} diff --git a/libraries/script-engine/src/WebSocketClass.cpp b/libraries/script-engine/src/WebSocketClass.cpp index 78ddd2d4740..8bb6e630822 100644 --- a/libraries/script-engine/src/WebSocketClass.cpp +++ b/libraries/script-engine/src/WebSocketClass.cpp @@ -16,6 +16,7 @@ #include "ScriptContext.h" #include "ScriptEngine.h" +#include "ScriptEngineCast.h" #include "ScriptEngineLogging.h" #include "ScriptValue.h" @@ -44,10 +45,10 @@ void WebSocketClass::initialize() { _binaryType = QStringLiteral("arraybuffer"); } -ScriptValuePointer WebSocketClass::constructor(ScriptContext* context, ScriptEngine* engine) { +ScriptValue WebSocketClass::constructor(ScriptContext* context, ScriptEngine* engine) { QString url; if (context->argumentCount() > 0) { - url = context->argument(0)->toString(); + url = context->argument(0).toString(); } return engine->newQObject(new WebSocketClass(engine, url), ScriptEngine::ScriptOwnership); } @@ -56,12 +57,12 @@ WebSocketClass::~WebSocketClass() { _webSocket->deleteLater(); } -void WebSocketClass::send(ScriptValuePointer message) { - if (message->isObject()) { +void WebSocketClass::send(const ScriptValue& message) { + if (message.isObject()) { QByteArray ba = scriptvalue_cast(message); _webSocket->sendBinaryMessage(ba); } else { - _webSocket->sendTextMessage(message->toString()); + _webSocket->sendTextMessage(message.toString()); } } @@ -91,14 +92,14 @@ void WebSocketClass::close(QWebSocketProtocol::CloseCode closeCode, QString reas */ void WebSocketClass::handleOnClose() { bool hasError = (_webSocket->error() != QAbstractSocket::UnknownSocketError); - if (_onCloseEvent->isFunction()) { + if (_onCloseEvent.isFunction()) { ScriptValueList args; - ScriptValuePointer arg = _engine->newObject(); - arg->setProperty("code", hasError ? QWebSocketProtocol::CloseCodeAbnormalDisconnection : _webSocket->closeCode()); - arg->setProperty("reason", _webSocket->closeReason()); - arg->setProperty("wasClean", !hasError); + ScriptValue arg = _engine->newObject(); + arg.setProperty("code", hasError ? QWebSocketProtocol::CloseCodeAbnormalDisconnection : _webSocket->closeCode()); + arg.setProperty("reason", _webSocket->closeReason()); + arg.setProperty("wasClean", !hasError); args << arg; - _onCloseEvent->call(ScriptValuePointer(), args); + _onCloseEvent.call(ScriptValue(), args); } } @@ -154,8 +155,8 @@ void WebSocketClass::handleOnClose() { * @typedef {number} WebSocket.SocketError */ void WebSocketClass::handleOnError(QAbstractSocket::SocketError error) { - if (_onErrorEvent->isFunction()) { - _onErrorEvent->call(); + if (_onErrorEvent.isFunction()) { + _onErrorEvent.call(); } } @@ -170,26 +171,26 @@ void WebSocketClass::handleOnError(QAbstractSocket::SocketError error) { * @property {string} data - The message content. */ void WebSocketClass::handleOnMessage(const QString& message) { - if (_onMessageEvent->isFunction()) { + if (_onMessageEvent.isFunction()) { ScriptValueList args; - ScriptValuePointer arg = _engine->newObject(); - arg->setProperty("data", message); + ScriptValue arg = _engine->newObject(); + arg.setProperty("data", message); args << arg; - _onMessageEvent->call(ScriptValuePointer(), args); + _onMessageEvent.call(ScriptValue(), args); } } void WebSocketClass::handleOnBinaryMessage(const QByteArray& message) { - if (_onMessageEvent->isFunction()) { + if (_onMessageEvent.isFunction()) { ScriptValueList args; - ScriptValuePointer arg = _engine->newObject(); - ScriptValuePointer arrayBuffer = _engine->newArrayBuffer(message); - if (arrayBuffer->isUndefined()) { + ScriptValue arg = _engine->newObject(); + ScriptValue arrayBuffer = _engine->newArrayBuffer(message); + if (arrayBuffer.isUndefined()) { qCWarning(scriptengine) << "WebSocketClass::handleOnBinaryMessage !ArrayBuffer"; } - arg->setProperty("data", arrayBuffer); + arg.setProperty("data", arrayBuffer); args << arg; - _onMessageEvent->call(ScriptValuePointer(), args); + _onMessageEvent.call(ScriptValue(), args); } } @@ -198,31 +199,31 @@ void WebSocketClass::handleOnBinaryMessage(const QByteArray& message) { * @callback WebSocket~onOpenCallback */ void WebSocketClass::handleOnOpen() { - if (_onOpenEvent->isFunction()) { - _onOpenEvent->call(); + if (_onOpenEvent.isFunction()) { + _onOpenEvent.call(); } } -ScriptValuePointer qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProtocol::CloseCode &closeCode) { +ScriptValue qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProtocol::CloseCode &closeCode) { return engine->newValue(closeCode); } -void qWSCloseCodeFromScriptValue(const ScriptValuePointer &object, QWebSocketProtocol::CloseCode &closeCode) { - closeCode = (QWebSocketProtocol::CloseCode)object->toUInt16(); +void qWSCloseCodeFromScriptValue(const ScriptValue &object, QWebSocketProtocol::CloseCode &closeCode) { + closeCode = (QWebSocketProtocol::CloseCode)object.toUInt16(); } -ScriptValuePointer webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in) { +ScriptValue webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in) { return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void webSocketFromScriptValue(const ScriptValuePointer &object, WebSocketClass* &out) { - out = qobject_cast(object->toQObject()); +void webSocketFromScriptValue(const ScriptValue &object, WebSocketClass* &out) { + out = qobject_cast(object.toQObject()); } -ScriptValuePointer wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState) { +ScriptValue wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState) { return engine->newValue(readyState); } -void wscReadyStateFromScriptValue(const ScriptValuePointer& object, WebSocketClass::ReadyState& readyState) { - readyState = (WebSocketClass::ReadyState)object->toUInt16(); +void wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState) { + readyState = (WebSocketClass::ReadyState)object.toUInt16(); } diff --git a/libraries/script-engine/src/WebSocketClass.h b/libraries/script-engine/src/WebSocketClass.h index 756c5c86777..f89d30a2c9d 100644 --- a/libraries/script-engine/src/WebSocketClass.h +++ b/libraries/script-engine/src/WebSocketClass.h @@ -17,12 +17,11 @@ #include #include -#include + +#include "ScriptValue.h" class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * Provides a bi-directional, event-driven communication session between the script and another WebSocket connection. It is a @@ -93,10 +92,10 @@ class WebSocketClass : public QObject { Q_PROPERTY(ulong bufferedAmount READ getBufferedAmount) Q_PROPERTY(QString extensions READ getExtensions) - Q_PROPERTY(ScriptValuePointer onclose READ getOnClose WRITE setOnClose) - Q_PROPERTY(ScriptValuePointer onerror READ getOnError WRITE setOnError) - Q_PROPERTY(ScriptValuePointer onmessage READ getOnMessage WRITE setOnMessage) - Q_PROPERTY(ScriptValuePointer onopen READ getOnOpen WRITE setOnOpen) + Q_PROPERTY(ScriptValue onclose READ getOnClose WRITE setOnClose) + Q_PROPERTY(ScriptValue onerror READ getOnError WRITE setOnError) + Q_PROPERTY(ScriptValue onmessage READ getOnMessage WRITE setOnMessage) + Q_PROPERTY(ScriptValue onopen READ getOnOpen WRITE setOnOpen) Q_PROPERTY(QString protocol READ getProtocol) Q_PROPERTY(WebSocketClass::ReadyState readyState READ getReadyState) @@ -112,7 +111,7 @@ class WebSocketClass : public QObject { WebSocketClass(ScriptEngine* engine, QWebSocket* qWebSocket); ~WebSocketClass(); - static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine); + static ScriptValue constructor(ScriptContext* context, ScriptEngine* engine); /*@jsdoc * The state of a WebSocket connection. @@ -173,17 +172,17 @@ class WebSocketClass : public QObject { } } - void setOnClose(ScriptValuePointer eventFunction) { _onCloseEvent = eventFunction; } - ScriptValuePointer getOnClose() { return _onCloseEvent; } + void setOnClose(const ScriptValue& eventFunction) { _onCloseEvent = eventFunction; } + ScriptValue getOnClose() { return _onCloseEvent; } - void setOnError(ScriptValuePointer eventFunction) { _onErrorEvent = eventFunction; } - ScriptValuePointer getOnError() { return _onErrorEvent; } + void setOnError(const ScriptValue& eventFunction) { _onErrorEvent = eventFunction; } + ScriptValue getOnError() { return _onErrorEvent; } - void setOnMessage(ScriptValuePointer eventFunction) { _onMessageEvent = eventFunction; } - ScriptValuePointer getOnMessage() { return _onMessageEvent; } + void setOnMessage(const ScriptValue& eventFunction) { _onMessageEvent = eventFunction; } + ScriptValue getOnMessage() { return _onMessageEvent; } - void setOnOpen(ScriptValuePointer eventFunction) { _onOpenEvent = eventFunction; } - ScriptValuePointer getOnOpen() { return _onOpenEvent; } + void setOnOpen(const ScriptValue& eventFunction) { _onOpenEvent = eventFunction; } + ScriptValue getOnOpen() { return _onOpenEvent; } public slots: @@ -192,7 +191,7 @@ public slots: * @function WebSocket.send * @param {string|object} message - The message to send. If an object, it is converted to a string. */ - void send(ScriptValuePointer message); + void send(const ScriptValue& message); /*@jsdoc * Closes the connection. @@ -232,10 +231,10 @@ public slots: QWebSocket* _webSocket; ScriptEngine* _engine; - ScriptValuePointer _onCloseEvent; - ScriptValuePointer _onErrorEvent; - ScriptValuePointer _onMessageEvent; - ScriptValuePointer _onOpenEvent; + ScriptValue _onCloseEvent; + ScriptValue _onErrorEvent; + ScriptValue _onMessageEvent; + ScriptValue _onOpenEvent; QString _binaryType; @@ -253,14 +252,14 @@ private slots: Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode); Q_DECLARE_METATYPE(WebSocketClass::ReadyState); -ScriptValuePointer qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProtocol::CloseCode& closeCode); -void qWSCloseCodeFromScriptValue(const ScriptValuePointer& object, QWebSocketProtocol::CloseCode& closeCode); +ScriptValue qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProtocol::CloseCode& closeCode); +void qWSCloseCodeFromScriptValue(const ScriptValue& object, QWebSocketProtocol::CloseCode& closeCode); -ScriptValuePointer webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in); -void webSocketFromScriptValue(const ScriptValuePointer &object, WebSocketClass* &out); +ScriptValue webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in); +void webSocketFromScriptValue(const ScriptValue &object, WebSocketClass* &out); -ScriptValuePointer wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState); -void wscReadyStateFromScriptValue(const ScriptValuePointer& object, WebSocketClass::ReadyState& readyState); +ScriptValue wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState); +void wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState); #endif // hifi_WebSocketClass_h diff --git a/libraries/script-engine/src/WebSocketServerClass.cpp b/libraries/script-engine/src/WebSocketServerClass.cpp index 17677a1fc69..304219952cb 100644 --- a/libraries/script-engine/src/WebSocketServerClass.cpp +++ b/libraries/script-engine/src/WebSocketServerClass.cpp @@ -26,21 +26,21 @@ WebSocketServerClass::WebSocketServerClass(ScriptEngine* engine, const QString& } } -ScriptValuePointer WebSocketServerClass::constructor(ScriptContext* context, ScriptEngine* engine) { +ScriptValue WebSocketServerClass::constructor(ScriptContext* context, ScriptEngine* engine) { // the serverName is used in handshakes QString serverName = QStringLiteral("HighFidelity - Scripted WebSocket Listener"); // port 0 will auto-assign a free port quint16 port = 0; - ScriptValuePointer callee = context->callee(); + ScriptValue callee = context->callee(); if (context->argumentCount() > 0) { - ScriptValuePointer options = context->argument(0); - ScriptValuePointer portOption = options->property(QStringLiteral("port")); - if (portOption->isValid() && portOption->isNumber()) { - port = portOption->toNumber(); + ScriptValue options = context->argument(0); + ScriptValue portOption = options.property(QStringLiteral("port")); + if (portOption.isValid() && portOption.isNumber()) { + port = portOption.toNumber(); } - ScriptValuePointer serverNameOption = options->property(QStringLiteral("serverName")); - if (serverNameOption->isValid() && serverNameOption->isString()) { - serverName = serverNameOption->toString(); + ScriptValue serverNameOption = options.property(QStringLiteral("serverName")); + if (serverNameOption.isValid() && serverNameOption.isString()) { + serverName = serverNameOption.toString(); } } return engine->newQObject(new WebSocketServerClass(engine, serverName, port), ScriptEngine::ScriptOwnership); diff --git a/libraries/script-engine/src/WebSocketServerClass.h b/libraries/script-engine/src/WebSocketServerClass.h index 49a87674f38..2ff2b98a953 100644 --- a/libraries/script-engine/src/WebSocketServerClass.h +++ b/libraries/script-engine/src/WebSocketServerClass.h @@ -18,12 +18,11 @@ #include #include #include "WebSocketClass.h" -#include + +#include "ScriptValue.h" class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * Manages {@link WebSocket}s in server entity and assignment client scripts. @@ -96,7 +95,7 @@ class WebSocketServerClass : public QObject { quint16 getPort() { return _webSocketServer.serverPort(); } bool isListening() { return _webSocketServer.isListening(); } - static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine); + static ScriptValue constructor(ScriptContext* context, ScriptEngine* engine); public slots: diff --git a/libraries/script-engine/src/WheelEvent.cpp b/libraries/script-engine/src/WheelEvent.cpp index 22c3f9f2a47..4cf238e65b4 100644 --- a/libraries/script-engine/src/WheelEvent.cpp +++ b/libraries/script-engine/src/WheelEvent.cpp @@ -81,22 +81,22 @@ WheelEvent::WheelEvent(const QWheelEvent& event) { * print(JSON.stringify(event)); * }); */ -ScriptValuePointer WheelEvent::toScriptValue(ScriptEngine* engine, const WheelEvent& event) { - ScriptValuePointer obj = engine->newObject(); - obj->setProperty("x", event.x); - obj->setProperty("y", event.y); - obj->setProperty("delta", event.delta); - obj->setProperty("orientation", event.orientation); - obj->setProperty("isLeftButton", event.isLeftButton); - obj->setProperty("isRightButton", event.isRightButton); - obj->setProperty("isMiddleButton", event.isMiddleButton); - obj->setProperty("isShifted", event.isShifted); - obj->setProperty("isMeta", event.isMeta); - obj->setProperty("isControl", event.isControl); - obj->setProperty("isAlt", event.isAlt); +ScriptValue WheelEvent::toScriptValue(ScriptEngine* engine, const WheelEvent& event) { + ScriptValue obj = engine->newObject(); + obj.setProperty("x", event.x); + obj.setProperty("y", event.y); + obj.setProperty("delta", event.delta); + obj.setProperty("orientation", event.orientation); + obj.setProperty("isLeftButton", event.isLeftButton); + obj.setProperty("isRightButton", event.isRightButton); + obj.setProperty("isMiddleButton", event.isMiddleButton); + obj.setProperty("isShifted", event.isShifted); + obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); return obj; } -void WheelEvent::fromScriptValue(const ScriptValuePointer& object, WheelEvent& event) { +void WheelEvent::fromScriptValue(const ScriptValue& object, WheelEvent& event) { // nothing for now... } diff --git a/libraries/script-engine/src/WheelEvent.h b/libraries/script-engine/src/WheelEvent.h index daf78c4a66e..74421cb10e9 100644 --- a/libraries/script-engine/src/WheelEvent.h +++ b/libraries/script-engine/src/WheelEvent.h @@ -17,11 +17,10 @@ #include #include -#include + +#include "ScriptValue.h" class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// Represents a mouse wheel event to the scripting engine. Exposed as WheelEvent class WheelEvent { @@ -29,8 +28,8 @@ class WheelEvent { WheelEvent(); WheelEvent(const QWheelEvent& event); - static ScriptValuePointer toScriptValue(ScriptEngine* engine, const WheelEvent& event); - static void fromScriptValue(const ScriptValuePointer& object, WheelEvent& event); + static ScriptValue toScriptValue(ScriptEngine* engine, const WheelEvent& event); + static void fromScriptValue(const ScriptValue& object, WheelEvent& event); int x; int y; diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 0518cbc17a7..fbac5120345 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -25,6 +25,7 @@ #include "ResourceRequestObserver.h" #include "ScriptContext.h" #include "ScriptEngine.h" +#include "ScriptEngineCast.h" #include "ScriptValue.h" Q_DECLARE_METATYPE(QByteArray*) @@ -43,15 +44,15 @@ XMLHttpRequestClass::~XMLHttpRequestClass() { if (_reply) { _reply->deleteLater(); } } -ScriptValuePointer XMLHttpRequestClass::constructor(ScriptContext* context, ScriptEngine* engine) { +ScriptValue XMLHttpRequestClass::constructor(ScriptContext* context, ScriptEngine* engine) { return engine->newQObject(new XMLHttpRequestClass(engine), ScriptEngine::ScriptOwnership); } -ScriptValuePointer XMLHttpRequestClass::getStatus() const { +ScriptValue XMLHttpRequestClass::getStatus() const { if (_reply) { return _engine->newValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); } - return ScriptValuePointer(0); + return ScriptValue(_engine->newValue(0)); } QString XMLHttpRequestClass::getStatusText() const { @@ -91,7 +92,7 @@ void XMLHttpRequestClass::requestDownloadProgress(qint64 bytesReceived, qint64 b } } -ScriptValuePointer XMLHttpRequestClass::getAllResponseHeaders() const { +ScriptValue XMLHttpRequestClass::getAllResponseHeaders() const { if (_reply) { QList headerList = _reply->rawHeaderPairs(); QByteArray headers; @@ -106,7 +107,7 @@ ScriptValuePointer XMLHttpRequestClass::getAllResponseHeaders() const { return _engine->newValue(""); } -ScriptValuePointer XMLHttpRequestClass::getResponseHeader(const QString& name) const { +ScriptValue XMLHttpRequestClass::getResponseHeader(const QString& name) const { if (_reply && _reply->hasRawHeader(name.toLatin1())) { return _engine->newValue(QString(_reply->rawHeader(name.toLatin1()))); } @@ -120,8 +121,8 @@ ScriptValuePointer XMLHttpRequestClass::getResponseHeader(const QString& name) c void XMLHttpRequestClass::setReadyState(ReadyState readyState) { if (readyState != _readyState) { _readyState = readyState; - if (_onReadyStateChange->isFunction()) { - _onReadyStateChange->call(_onReadyStateChange->engine()->nullValue()); + if (_onReadyStateChange.isFunction()) { + _onReadyStateChange.call(_onReadyStateChange.engine()->nullValue()); } } } @@ -160,14 +161,14 @@ void XMLHttpRequestClass::send() { send(_engine->nullValue()); } -void XMLHttpRequestClass::send(const ScriptValuePointer& data) { +void XMLHttpRequestClass::send(const ScriptValue& data) { if (_readyState == OPENED && !_reply) { if (!data.isNull()) { - if (data->isObject()) { + if (data.isObject()) { _sendData = scriptvalue_cast(data); } else { - _sendData = data->toString().toUtf8(); + _sendData = data.toString().toUtf8(); } } @@ -197,8 +198,8 @@ void XMLHttpRequestClass::doSend() { * @callback XMLHttpRequest~onTimeoutCallback */ void XMLHttpRequestClass::requestTimeout() { - if (_onTimeout->isFunction()) { - _onTimeout->call(_engine->nullValue()); + if (_onTimeout.isFunction()) { + _onTimeout.call(_engine->nullValue()); } abortRequest(); _errorCode = QNetworkReply::TimeoutError; @@ -219,7 +220,7 @@ void XMLHttpRequestClass::requestFinished() { if (_responseType == "json") { _responseData = _engine->evaluate("(" + QString(_rawResponseData.data()) + ")"); - if (_responseData->isError()) { + if (_responseData.isError()) { _engine->clearExceptions(); _responseData = _engine->nullValue(); } diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h index 08fcba5df20..7e38a2155bd 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.h +++ b/libraries/script-engine/src/XMLHttpRequestClass.h @@ -20,13 +20,11 @@ #include #include #include -#include #include "ScriptEngine.h" +#include "ScriptValue.h" class ScriptContext; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /* XMlHttpRequest object @@ -58,7 +56,7 @@ XMlHttpRequest.open(QString,QString,bool,QString) function XMlHttpRequest.open(QString,QString,bool) function XMlHttpRequest.open(QString,QString) function XMlHttpRequest.send() function -XMlHttpRequest.send(ScriptValuePointer) function +XMlHttpRequest.send(ScriptValue) function XMlHttpRequest.getAllResponseHeaders() function XMlHttpRequest.getResponseHeader(QString) function */ @@ -159,13 +157,13 @@ XMlHttpRequest.getResponseHeader(QString) function /// Provides the XMLHttpRequest scripting interface class XMLHttpRequestClass : public QObject { Q_OBJECT - Q_PROPERTY(ScriptValuePointer response READ getResponse) - Q_PROPERTY(ScriptValuePointer responseText READ getResponseText) + Q_PROPERTY(ScriptValue response READ getResponse) + Q_PROPERTY(ScriptValue responseText READ getResponseText) Q_PROPERTY(QString responseType READ getResponseType WRITE setResponseType) - Q_PROPERTY(ScriptValuePointer status READ getStatus) + Q_PROPERTY(ScriptValue status READ getStatus) Q_PROPERTY(QString statusText READ getStatusText) - Q_PROPERTY(ScriptValuePointer readyState READ getReadyState) - Q_PROPERTY(ScriptValuePointer errorCode READ getError) + Q_PROPERTY(ScriptValue readyState READ getReadyState) + Q_PROPERTY(ScriptValue errorCode READ getError) Q_PROPERTY(int timeout READ getTimeout WRITE setTimeout) Q_PROPERTY(int UNSENT READ getUnsent) @@ -175,8 +173,8 @@ class XMLHttpRequestClass : public QObject { Q_PROPERTY(int DONE READ getDone) // Callbacks - Q_PROPERTY(ScriptValuePointer ontimeout READ getOnTimeout WRITE setOnTimeout) - Q_PROPERTY(ScriptValuePointer onreadystatechange READ getOnReadyStateChange WRITE setOnReadyStateChange) + Q_PROPERTY(ScriptValue ontimeout READ getOnTimeout WRITE setOnTimeout) + Q_PROPERTY(ScriptValue onreadystatechange READ getOnReadyStateChange WRITE setOnReadyStateChange) public: XMLHttpRequestClass(ScriptEngine* engine); ~XMLHttpRequestClass(); @@ -216,23 +214,23 @@ class XMLHttpRequestClass : public QObject { int getLoading() const { return LOADING; }; int getDone() const { return DONE; }; - static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine); + static ScriptValue constructor(ScriptContext* context, ScriptEngine* engine); int getTimeout() const { return _timeout; } void setTimeout(int timeout) { _timeout = timeout; } - ScriptValuePointer getResponse() const { return _responseData; } - ScriptValuePointer getResponseText() const { return _engine->newValue(QString(_rawResponseData.data())); } + ScriptValue getResponse() const { return _responseData; } + ScriptValue getResponseText() const { return _engine->newValue(QString(_rawResponseData.data())); } QString getResponseType() const { return _responseType; } void setResponseType(const QString& responseType) { _responseType = responseType; } - ScriptValuePointer getReadyState() const { return _engine->newValue(_readyState); } - ScriptValuePointer getError() const { return _engine->newValue(_errorCode); } - ScriptValuePointer getStatus() const; + ScriptValue getReadyState() const { return _engine->newValue(_readyState); } + ScriptValue getError() const { return _engine->newValue(_errorCode); } + ScriptValue getStatus() const; QString getStatusText() const; - ScriptValuePointer getOnTimeout() const { return _onTimeout; } - void setOnTimeout(ScriptValuePointer function) { _onTimeout = function; } - ScriptValuePointer getOnReadyStateChange() const { return _onReadyStateChange; } - void setOnReadyStateChange(ScriptValuePointer function) { _onReadyStateChange = function; } + ScriptValue getOnTimeout() const { return _onTimeout; } + void setOnTimeout(const ScriptValue& function) { _onTimeout = function; } + ScriptValue getOnReadyStateChange() const { return _onReadyStateChange; } + void setOnReadyStateChange(const ScriptValue& function) { _onReadyStateChange = function; } public slots: @@ -271,14 +269,14 @@ public slots: * @param {*} [data] - The data to send. */ void send(); - void send(const ScriptValuePointer& data); + void send(const ScriptValue& data); /*@jsdoc * Gets the response headers. * @function XMLHttpRequest.getAllResponseHeaders * @returns {string} The response headers, separated by "\n" characters. */ - ScriptValuePointer getAllResponseHeaders() const; + ScriptValue getAllResponseHeaders() const; /*@jsdoc * Gets a response header. @@ -286,7 +284,7 @@ public slots: * @param {string} name - * @returns {string} The response header. */ - ScriptValuePointer getResponseHeader(const QString& name) const; + ScriptValue getResponseHeader(const QString& name) const; signals: @@ -313,9 +311,9 @@ public slots: QNetworkReply* _reply { nullptr }; QByteArray _sendData; QByteArray _rawResponseData; - ScriptValuePointer _responseData; - ScriptValuePointer _onTimeout; - ScriptValuePointer _onReadyStateChange; + ScriptValue _responseData; + ScriptValue _onTimeout; + ScriptValue _onReadyStateChange; ReadyState _readyState { XMLHttpRequestClass::UNSENT }; /*@jsdoc diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp index 798d93a0eae..75172bed12e 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp @@ -28,18 +28,18 @@ int ScriptContextQtWrapper::argumentCount() const { return _context->argumentCount(); } -ScriptValuePointer ScriptContextQtWrapper::argument(int index) const { +ScriptValue ScriptContextQtWrapper::argument(int index) const { QScriptValue result = _context->argument(index); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } QStringList ScriptContextQtWrapper::backtrace() const { return _context->backtrace(); } -ScriptValuePointer ScriptContextQtWrapper::callee() const { +ScriptValue ScriptContextQtWrapper::callee() const { QScriptValue result = _context->callee(); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } ScriptEnginePointer ScriptContextQtWrapper::engine() const { @@ -55,23 +55,23 @@ ScriptContextPointer ScriptContextQtWrapper::parentContext() const { return result ? ScriptContextPointer(new ScriptContextQtWrapper(_engine, result)) : ScriptContextPointer(); } -ScriptValuePointer ScriptContextQtWrapper::thisObject() const { +ScriptValue ScriptContextQtWrapper::thisObject() const { QScriptValue result = _context->thisObject(); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } -ScriptValuePointer ScriptContextQtWrapper::throwError(const QString& text) { +ScriptValue ScriptContextQtWrapper::throwError(const QString& text) { QScriptValue result = _context->throwError(text); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } -ScriptValuePointer ScriptContextQtWrapper::throwValue(const ScriptValuePointer& value) { +ScriptValue ScriptContextQtWrapper::throwValue(const ScriptValue& value) { ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); if (!unwrapped) { return _engine->undefinedValue(); } QScriptValue result = _context->throwValue(unwrapped->toQtValue()); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h index b2f7726d85c..db542799c83 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h @@ -15,16 +15,14 @@ #ifndef hifi_ScriptContextQtWrapper_h #define hifi_ScriptContextQtWrapper_h -#include #include #include #include "../ScriptContext.h" +#include "../ScriptValue.h" class QScriptContext; class ScriptEngineQtScript; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /// [QtScript] Implements ScriptContext for QtScript and translates calls for QScriptContextInfo class ScriptContextQtWrapper : public ScriptContext { @@ -35,15 +33,15 @@ class ScriptContextQtWrapper : public ScriptContext { public: // ScriptContext implementation virtual int argumentCount() const; - virtual ScriptValuePointer argument(int index) const; + virtual ScriptValue argument(int index) const; virtual QStringList backtrace() const; - virtual ScriptValuePointer callee() const; + virtual ScriptValue callee() const; virtual ScriptEnginePointer engine() const; virtual ScriptFunctionContextPointer functionContext() const; virtual ScriptContextPointer parentContext() const; - virtual ScriptValuePointer thisObject() const; - virtual ScriptValuePointer throwError(const QString& text); - virtual ScriptValuePointer throwValue(const ScriptValuePointer& value); + virtual ScriptValue thisObject() const; + virtual ScriptValue throwError(const QString& text); + virtual ScriptValue throwValue(const ScriptValue& value); private: // storage QScriptContext* _context; diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index 7700d778d2c..f18bf1d0102 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -62,7 +62,7 @@ static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_P static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; -Q_DECLARE_METATYPE(ScriptValuePointer); +Q_DECLARE_METATYPE(ScriptValue); Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) int qfunctionSignatureMetaID = qRegisterMetaType(); @@ -120,26 +120,26 @@ QScriptValue ScriptEngineQtScript::makeError(const QScriptValue& _other, const Q return err; } -ScriptValuePointer ScriptEngineQtScript::makeError(const ScriptValuePointer& _other, const QString& type) { +ScriptValue ScriptEngineQtScript::makeError(const ScriptValue& _other, const QString& type) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return nullValue(); } ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(_other); QScriptValue other; - if (_other->isString()) { + if (_other.isString()) { other = QScriptEngine::newObject(); - other.setProperty("message", _other->toString()); + other.setProperty("message", _other.toString()); } else if (unwrapped) { other = unwrapped->toQtValue(); } else { - other = QScriptEngine::newVariant(_other->toVariant()); + other = QScriptEngine::newVariant(_other.toVariant()); } QScriptValue result = makeError(other, type); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } // check syntax and when there are issues returns an actual "SyntaxError" with the details -ScriptValuePointer ScriptEngineQtScript::lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber) { +ScriptValue ScriptEngineQtScript::lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return nullValue(); } @@ -158,13 +158,13 @@ ScriptValuePointer ScriptEngineQtScript::lintScript(const QString& sourceCode, c const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, fileName, line, column); err.setProperty("formatted", message); } - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(err))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(err))); } return undefinedValue(); } // this pulls from the best available information to create a detailed snapshot of the current exception -ScriptValuePointer ScriptEngineQtScript::cloneUncaughtException(const QString& extraDetail) { +ScriptValue ScriptEngineQtScript::cloneUncaughtException(const QString& extraDetail) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return nullValue(); } @@ -178,17 +178,17 @@ ScriptValuePointer ScriptEngineQtScript::cloneUncaughtException(const QString& e // not sure why Qt does't offer uncaughtExceptionFileName -- but the line number // on its own is often useless/wrong if arbitrarily married to a filename. // when the error object already has this info, it seems to be the most reliable - auto fileName = exception->property("fileName")->toString(); - auto lineNumber = exception->property("lineNumber")->toInt32(); + auto fileName = exception.property("fileName").toString(); + auto lineNumber = exception.property("lineNumber").toInt32(); // the backtrace, on the other hand, seems most reliable taken from uncaughtExceptionBacktrace auto backtrace = uncaughtExceptionBacktrace(); if (backtrace.isEmpty()) { // fallback to the error object - backtrace = exception->property("stack")->toString().split(ScriptManager::SCRIPT_BACKTRACE_SEP); + backtrace = exception.property("stack").toString().split(ScriptManager::SCRIPT_BACKTRACE_SEP); } // the ad hoc "detail" property can be used now to embed additional clues - auto detail = exception->property("detail")->toString(); + auto detail = exception.property("detail").toString(); if (detail.isEmpty()) { detail = extraDetail; } else if (!extraDetail.isEmpty()) { @@ -212,15 +212,15 @@ ScriptValuePointer ScriptEngineQtScript::cloneUncaughtException(const QString& e } } } - err->setProperty("fileName", fileName); - err->setProperty("lineNumber", lineNumber); - err->setProperty("detail", detail); - err->setProperty("stack", backtrace.join(ScriptManager::SCRIPT_BACKTRACE_SEP)); + err.setProperty("fileName", fileName); + err.setProperty("lineNumber", lineNumber); + err.setProperty("detail", detail); + err.setProperty("stack", backtrace.join(ScriptManager::SCRIPT_BACKTRACE_SEP)); #ifdef DEBUG_JS_EXCEPTIONS - err->setProperty("_fileName", exception.property("fileName").toString()); - err->setProperty("_stack", uncaughtExceptionBacktrace().join(SCRIPT_BACKTRACE_SEP)); - err->setProperty("_lineNumber", uncaughtExceptionLineNumber()); + err.setProperty("_fileName", exception.property("fileName").toString()); + err.setProperty("_stack", uncaughtExceptionBacktrace().join(SCRIPT_BACKTRACE_SEP)); + err.setProperty("_lineNumber", uncaughtExceptionLineNumber()); #endif return err; } @@ -237,7 +237,7 @@ bool ScriptEngineQtScript::raiseException(const QScriptValue& exception) { // we are within a pure C++ stack frame (ie: being called directly by other C++ code) // in this case no context information is available so just emit the exception for reporting QScriptValue thrown = makeError(exception); - emit _manager->unhandledException(ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(thrown)))); + emit _manager->unhandledException(ScriptValue(new ScriptValueQtWrapper(this, std::move(thrown)))); } return false; } @@ -383,13 +383,13 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { return QScriptValue(); } -static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValuePointer& src) { +static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValue& src) { return ScriptValueQtWrapper::fullUnwrap(static_cast(engine), src); } -static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValuePointer& dest) { +static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValue& dest) { ScriptEngineQtScript* engine = static_cast(src.engine()); - dest = ScriptValuePointer(new ScriptValueQtWrapper(engine, src)); + dest = ScriptValue(new ScriptValueQtWrapper(engine, src)); } ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : @@ -408,17 +408,17 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : } else { // ... but may not always be available -- so if needed we fallback to the passed exception QScriptValue thrown = makeError(exception); - emit _manager->unhandledException(ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(thrown)))); + emit _manager->unhandledException(ScriptValue(new ScriptValueQtWrapper(this, std::move(thrown)))); } }, Qt::DirectConnection); moveToThread(scriptManager->thread()); } QScriptValue null = QScriptEngine::nullValue(); - _nullValue = ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(null))); + _nullValue = ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(null))); QScriptValue undefined = QScriptEngine::undefinedValue(); - _undefinedValue = ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(undefined))); + _undefinedValue = ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(undefined))); QScriptEngine::setProcessEventsInterval(MSECS_PER_SECOND); } @@ -478,14 +478,14 @@ void ScriptEngineQtScript::registerValue(const QString& valueName, QScriptValue QStringList pathToValue = valueName.split("."); int partsToGo = pathToValue.length(); - QScriptValue partObject = globalObject(); + QScriptValue partObject = QScriptEngine::globalObject(); for (const auto& pathPart : pathToValue) { partsToGo--; if (!partObject.property(pathPart).isValid()) { if (partsToGo > 0) { //QObject *object = new QObject; - QScriptValue partValue = newArray(); //newQObject(object, QScriptEngine::ScriptOwnership); + QScriptValue partValue = QScriptEngine::newArray(); //newQObject(object, QScriptEngine::ScriptOwnership); partObject.setProperty(pathPart, partValue); } else { partObject.setProperty(pathPart, value); @@ -554,7 +554,7 @@ void ScriptEngineQtScript::registerFunction(const QString& name, ScriptEngine::F #endif auto scriptFun = newFunction(functionSignature, numArguments); - globalObject()->setProperty(name, scriptFun); + globalObject().setProperty(name, scriptFun); } void ScriptEngineQtScript::registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { @@ -594,10 +594,10 @@ void ScriptEngineQtScript::registerFunction(const QString& parent, const QString qCDebug(scriptengine) << "ScriptEngineQtScript::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; #endif - auto object = globalObject()->property(parent); - if (object->isValid()) { + auto object = globalObject().property(parent); + if (object.isValid()) { auto scriptFun = newFunction(functionSignature, numArguments); - object->setProperty(name, scriptFun); + object.setProperty(name, scriptFun); } } @@ -656,18 +656,18 @@ void ScriptEngineQtScript::registerGetterSetter(const QString& name, ScriptEngin auto getterFunction = newFunction(getter); if (!parent.isNull() && !parent.isEmpty()) { - auto object = globalObject()->property(parent); - if (object->isValid()) { - object->setProperty(name, setterFunction, ScriptValue::PropertySetter); - object->setProperty(name, getterFunction, ScriptValue::PropertyGetter); + auto object = globalObject().property(parent); + if (object.isValid()) { + object.setProperty(name, setterFunction, ScriptValue::PropertySetter); + object.setProperty(name, getterFunction, ScriptValue::PropertyGetter); } } else { - globalObject()->setProperty(name, setterFunction, ScriptValue::PropertySetter); - globalObject()->setProperty(name, getterFunction, ScriptValue::PropertyGetter); + globalObject().setProperty(name, setterFunction, ScriptValue::PropertySetter); + globalObject().setProperty(name, getterFunction, ScriptValue::PropertyGetter); } } -ScriptValuePointer ScriptEngineQtScript::evaluateInClosure(const ScriptValuePointer& _closure, +ScriptValue ScriptEngineQtScript::evaluateInClosure(const ScriptValue& _closure, const ScriptProgramPointer& _program) { PROFILE_RANGE(script, "evaluateInClosure"); if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { @@ -712,7 +712,7 @@ ScriptValuePointer ScriptEngineQtScript::evaluateInClosure(const ScriptValuePoin #ifdef DEBUG_JS qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName); #endif - ScriptValuePointer result; + ScriptValue result; { auto qResult = QScriptEngine::evaluate(program); @@ -724,7 +724,7 @@ ScriptValuePointer ScriptEngineQtScript::evaluateInClosure(const ScriptValuePoin #endif result = err; } else { - result = ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(qResult))); + result = ScriptValue(new ScriptValueQtWrapper(this, std::move(qResult))); } } #ifdef DEBUG_JS @@ -742,19 +742,19 @@ ScriptValuePointer ScriptEngineQtScript::evaluateInClosure(const ScriptValuePoin return result; } -ScriptValuePointer ScriptEngineQtScript::evaluate(const QString& sourceCode, const QString& fileName) { +ScriptValue ScriptEngineQtScript::evaluate(const QString& sourceCode, const QString& fileName) { if (_manager && _manager->isStopped()) { return undefinedValue(); // bail early } if (QThread::currentThread() != QScriptEngine::thread()) { - ScriptValuePointer result; + ScriptValue result; #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "sourceCode:" << sourceCode << " fileName:" << fileName; #endif BLOCKING_INVOKE_METHOD(this, "evaluate", - Q_RETURN_ARG(ScriptValuePointer, result), + Q_RETURN_ARG(ScriptValue, result), Q_ARG(const QString&, sourceCode), Q_ARG(const QString&, fileName)); return result; @@ -762,9 +762,9 @@ ScriptValuePointer ScriptEngineQtScript::evaluate(const QString& sourceCode, con // Check syntax auto syntaxError = lintScript(sourceCode, fileName); - if (syntaxError->isError()) { + if (syntaxError.isError()) { if (!isEvaluating()) { - syntaxError->setProperty("detail", "evaluate"); + syntaxError.setProperty("detail", "evaluate"); } raiseException(syntaxError); maybeEmitUncaughtException("lint"); @@ -782,22 +782,22 @@ ScriptValuePointer ScriptEngineQtScript::evaluate(const QString& sourceCode, con QScriptValue result = QScriptEngine::evaluate(program); maybeEmitUncaughtException("evaluate"); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -Q_INVOKABLE ScriptValuePointer ScriptEngineQtScript::evaluate(const ScriptProgramPointer& program) { +Q_INVOKABLE ScriptValue ScriptEngineQtScript::evaluate(const ScriptProgramPointer& program) { if (_manager && _manager->isStopped()) { return undefinedValue(); // bail early } if (QThread::currentThread() != QScriptEngine::thread()) { - ScriptValuePointer result; + ScriptValue result; #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineQtScript::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "sourceCode:" << sourceCode << " fileName:" << fileName; #endif BLOCKING_INVOKE_METHOD(this, "evaluate", - Q_RETURN_ARG(ScriptValuePointer, result), + Q_RETURN_ARG(ScriptValue, result), Q_ARG(const ScriptProgramPointer&, program)); return result; } @@ -822,7 +822,7 @@ Q_INVOKABLE ScriptValuePointer ScriptEngineQtScript::evaluate(const ScriptProgra QScriptValue result = QScriptEngine::evaluate(qProgram); maybeEmitUncaughtException("evaluate"); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } @@ -849,21 +849,21 @@ void ScriptEngineQtScript::print(const QString& message) { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ScriptEngine implementation -ScriptValuePointer ScriptEngineQtScript::globalObject() const { +ScriptValue ScriptEngineQtScript::globalObject() const { QScriptValue global = QScriptEngine::globalObject(); // can't cache the value as it may change - return ScriptValuePointer(new ScriptValueQtWrapper(const_cast < ScriptEngineQtScript*>(this), std::move(global))); + return ScriptValue(new ScriptValueQtWrapper(const_cast < ScriptEngineQtScript*>(this), std::move(global))); } ScriptManager* ScriptEngineQtScript::manager() const { return _manager; } -ScriptValuePointer ScriptEngineQtScript::newArray(uint length) { +ScriptValue ScriptEngineQtScript::newArray(uint length) { QScriptValue result = QScriptEngine::newArray(length); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newArrayBuffer(const QByteArray& message) { +ScriptValue ScriptEngineQtScript::newArrayBuffer(const QByteArray& message) { QScriptValue data = QScriptEngine::newVariant(QVariant::fromValue(message)); QScriptValue ctor = QScriptEngine::globalObject().property("ArrayBuffer"); auto array = qscriptvalue_cast(ctor.data()); @@ -871,12 +871,12 @@ ScriptValuePointer ScriptEngineQtScript::newArrayBuffer(const QByteArray& messag return undefinedValue(); } QScriptValue result = QScriptEngine::newObject(array, data); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newObject() { +ScriptValue ScriptEngineQtScript::newObject() { QScriptValue result = QScriptEngine::newObject(); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, const QString& fileName) { @@ -884,66 +884,66 @@ ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, return ScriptProgramPointer(new ScriptProgramQtWrapper(this, result)); } -ScriptValuePointer ScriptEngineQtScript::newQObject(QObject* object, +ScriptValue ScriptEngineQtScript::newQObject(QObject* object, ScriptEngine::ValueOwnership ownership, const ScriptEngine::QObjectWrapOptions& options) { QScriptValue result = QScriptEngine::newQObject(object, static_cast(ownership), (QScriptEngine::QObjectWrapOptions)((int)options | DEFAULT_QOBJECT_WRAP_OPTIONS)); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newValue(bool value) { +ScriptValue ScriptEngineQtScript::newValue(bool value) { QScriptValue result(this, value); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newValue(int value) { +ScriptValue ScriptEngineQtScript::newValue(int value) { QScriptValue result(this, value); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newValue(uint value) { +ScriptValue ScriptEngineQtScript::newValue(uint value) { QScriptValue result(this, value); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newValue(double value) { +ScriptValue ScriptEngineQtScript::newValue(double value) { QScriptValue result(this, value); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newValue(const QString& value) { +ScriptValue ScriptEngineQtScript::newValue(const QString& value) { QScriptValue result(this, value); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newValue(const QLatin1String& value) { +ScriptValue ScriptEngineQtScript::newValue(const QLatin1String& value) { QScriptValue result(this, value); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newValue(const char* value) { +ScriptValue ScriptEngineQtScript::newValue(const char* value) { QScriptValue result(this, value); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::newVariant(const QVariant& value) { +ScriptValue ScriptEngineQtScript::newVariant(const QVariant& value) { QScriptValue result = QScriptEngine::newVariant(value); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } -ScriptValuePointer ScriptEngineQtScript::nullValue() { +ScriptValue ScriptEngineQtScript::nullValue() { return _nullValue; } -void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype){ +void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValue& prototype){ ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype); if (unwrappedPrototype) { QScriptEngine::setDefaultPrototype(metaTypeId, unwrappedPrototype->toQtValue()); } } -ScriptValuePointer ScriptEngineQtScript::undefinedValue() { +ScriptValue ScriptEngineQtScript::undefinedValue() { return _undefinedValue; } @@ -974,14 +974,14 @@ bool ScriptEngineQtScript::isEvaluating() const { return QScriptEngine::isEvaluating(); } -ScriptValuePointer ScriptEngineQtScript::newFunction(ScriptEngine::FunctionSignature fun, int length) { +ScriptValue ScriptEngineQtScript::newFunction(ScriptEngine::FunctionSignature fun, int length) { auto innerFunc = [](QScriptContext* _context, QScriptEngine* _engine) -> QScriptValue { auto callee = _context->callee(); QVariant funAddr = callee.property("_func").toVariant(); ScriptEngine::FunctionSignature fun = reinterpret_cast(funAddr.toULongLong()); ScriptEngineQtScript* engine = static_cast(_engine); ScriptContextQtWrapper context(engine, _context); - ScriptValuePointer result = fun(&context, engine); + ScriptValue result = fun(&context, engine); ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(result); return unwrapped ? unwrapped->toQtValue() : QScriptValue(); }; @@ -989,7 +989,7 @@ ScriptValuePointer ScriptEngineQtScript::newFunction(ScriptEngine::FunctionSigna QScriptValue result = QScriptEngine::newFunction(innerFunc, length); auto funAddr = QScriptEngine::newVariant(QVariant(reinterpret_cast(fun))); result.setProperty("_func", funAddr, QScriptValue::PropertyFlags(QScriptValue::ReadOnly + QScriptValue::Undeletable + QScriptValue::SkipInEnumeration)); - return ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } void ScriptEngineQtScript::setObjectName(const QString& name) { @@ -1012,9 +1012,9 @@ void ScriptEngineQtScript::setThread(QThread* thread) { moveToThread(thread); } -ScriptValuePointer ScriptEngineQtScript::uncaughtException() const { +ScriptValue ScriptEngineQtScript::uncaughtException() const { QScriptValue result = QScriptEngine::uncaughtException(); - return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(result))); } QStringList ScriptEngineQtScript::uncaughtExceptionBacktrace() const { @@ -1025,18 +1025,18 @@ int ScriptEngineQtScript::uncaughtExceptionLineNumber() const { return QScriptEngine::uncaughtExceptionLineNumber(); } -bool ScriptEngineQtScript::raiseException(const ScriptValuePointer& exception) { +bool ScriptEngineQtScript::raiseException(const ScriptValue& exception) { ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(exception); - QScriptValue qException = unwrapped ? unwrapped->toQtValue() : QScriptEngine::newVariant(exception->toVariant()); + QScriptValue qException = unwrapped ? unwrapped->toQtValue() : QScriptEngine::newVariant(exception.toVariant()); return raiseException(qException); } -ScriptValuePointer ScriptEngineQtScript::create(int type, const void* ptr) { +ScriptValue ScriptEngineQtScript::create(int type, const void* ptr) { QScriptValue result = qScriptValueFromValue_helper(this, type, ptr); - return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(result))); } -bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, void* ptr) { +bool ScriptEngineQtScript::convert(const ScriptValue& value, int type, void* ptr) { ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); if (unwrapped == nullptr) { return false; @@ -1052,13 +1052,13 @@ class CustomTypeInstance { static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) { ScriptEngineQtScript* unwrappedEngine = static_cast(engine); - ScriptValuePointer dest = marshalFunc(unwrappedEngine, src); + ScriptValue dest = marshalFunc(unwrappedEngine, src); return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest); } static void internalDemarshalFunc(const QScriptValue& src, void* dest) { ScriptEngineQtScript* unwrappedEngine = static_cast(src.engine()); - ScriptValuePointer wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src)); + ScriptValue wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src)); demarshalFunc(wrappedSrc, dest); } }; @@ -1094,7 +1094,7 @@ ScriptEngine::DemarshalFunction CustomTypeInstance::demarshalFunc; void ScriptEngineQtScript::registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, ScriptEngine::DemarshalFunction demarshalFunc, - const ScriptValuePointer& prototype) + const ScriptValue& prototype) { QScriptValue unwrapped = ScriptValueQtWrapper::fullUnwrap(this, prototype); QScriptEngine::MarshalFunction internalMarshalFunc; diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index af127988a0a..ada261ec3c8 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -47,51 +47,51 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q public: // ScriptEngine implementation virtual void abortEvaluation(); virtual void clearExceptions(); - virtual ScriptValuePointer cloneUncaughtException(const QString& detail = QString()); + virtual ScriptValue cloneUncaughtException(const QString& detail = QString()); virtual ScriptContext* currentContext() const; - //virtual ScriptValuePointer evaluate(const QString& program, const QString& fileName = QString()); - //virtual ScriptValuePointer evaluate(const ScriptProgramPointer &program); - //virtual ScriptValuePointer evaluateInClosure(const ScriptValuePointer& locals, const ScriptProgramPointer& program); - virtual ScriptValuePointer globalObject() const; + //virtual ScriptValue evaluate(const QString& program, const QString& fileName = QString()); + //virtual ScriptValue evaluate(const ScriptProgramPointer &program); + //virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program); + virtual ScriptValue globalObject() const; virtual bool hasUncaughtException() const; virtual bool isEvaluating() const; - virtual ScriptValuePointer lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1); - virtual ScriptValuePointer makeError(const ScriptValuePointer& other, const QString& type = "Error"); + virtual ScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1); + virtual ScriptValue makeError(const ScriptValue& other, const QString& type = "Error"); virtual ScriptManager* manager() const; // if there is a pending exception and we are at the top level (non-recursive) stack frame, this emits and resets it virtual bool maybeEmitUncaughtException(const QString& debugHint = QString()); - virtual ScriptValuePointer newArray(uint length = 0); - virtual ScriptValuePointer newArrayBuffer(const QByteArray& message); - virtual ScriptValuePointer newFunction(ScriptEngine::FunctionSignature fun, int length = 0); - virtual ScriptValuePointer newObject(); + virtual ScriptValue newArray(uint length = 0); + virtual ScriptValue newArrayBuffer(const QByteArray& message); + virtual ScriptValue newFunction(ScriptEngine::FunctionSignature fun, int length = 0); + virtual ScriptValue newObject(); virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName); - virtual ScriptValuePointer newQObject(QObject *object, ScriptEngine::ValueOwnership ownership = ScriptEngine::QtOwnership, + virtual ScriptValue newQObject(QObject *object, ScriptEngine::ValueOwnership ownership = ScriptEngine::QtOwnership, const ScriptEngine::QObjectWrapOptions &options = ScriptEngine::QObjectWrapOptions()); - virtual ScriptValuePointer newValue(bool value); - virtual ScriptValuePointer newValue(int value); - virtual ScriptValuePointer newValue(uint value); - virtual ScriptValuePointer newValue(double value); - virtual ScriptValuePointer newValue(const QString& value); - virtual ScriptValuePointer newValue(const QLatin1String& value); - virtual ScriptValuePointer newValue(const char* value); - virtual ScriptValuePointer newVariant(const QVariant& value); - virtual ScriptValuePointer nullValue(); - virtual bool raiseException(const ScriptValuePointer& exception); + virtual ScriptValue newValue(bool value); + virtual ScriptValue newValue(int value); + virtual ScriptValue newValue(uint value); + virtual ScriptValue newValue(double value); + virtual ScriptValue newValue(const QString& value); + virtual ScriptValue newValue(const QLatin1String& value); + virtual ScriptValue newValue(const char* value); + virtual ScriptValue newVariant(const QVariant& value); + virtual ScriptValue nullValue(); + virtual bool raiseException(const ScriptValue& exception); //virtual void registerEnum(const QString& enumName, QMetaEnum newEnum); //Q_INVOKABLE virtual void registerFunction(const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); //Q_INVOKABLE virtual void registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); //Q_INVOKABLE virtual void registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent = QString("")); //virtual void registerGlobalObject(const QString& name, QObject* object); - virtual void setDefaultPrototype(int metaTypeId, const ScriptValuePointer& prototype); + virtual void setDefaultPrototype(int metaTypeId, const ScriptValue& prototype); virtual void setObjectName(const QString& name); virtual bool setProperty(const char* name, const QVariant& value); virtual void setProcessEventsInterval(int interval); virtual QThread* thread() const; virtual void setThread(QThread* thread); - virtual ScriptValuePointer undefinedValue(); - virtual ScriptValuePointer uncaughtException() const; + virtual ScriptValue undefinedValue(); + virtual ScriptValue uncaughtException() const; virtual QStringList uncaughtExceptionBacktrace() const; virtual int uncaughtExceptionLineNumber() const; @@ -203,10 +203,10 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q * @deprecated This function is deprecated and will be removed. */ /// evaluate some code in the context of the ScriptEngineQtScript and return the result - Q_INVOKABLE virtual ScriptValuePointer evaluate(const QString& program, const QString& fileName); // this is also used by the script tool widget + Q_INVOKABLE virtual ScriptValue evaluate(const QString& program, const QString& fileName); // this is also used by the script tool widget - Q_INVOKABLE virtual ScriptValuePointer evaluate(const ScriptProgramPointer& program); + Q_INVOKABLE virtual ScriptValue evaluate(const ScriptProgramPointer& program); /*@jsdoc * @function Script.evaluateInClosure @@ -215,7 +215,7 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q * @returns {object} Object. * @deprecated This function is deprecated and will be removed. */ - Q_INVOKABLE virtual ScriptValuePointer evaluateInClosure(const ScriptValuePointer& locals, const ScriptProgramPointer& program); + Q_INVOKABLE virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program); /*@jsdoc * Checks whether the application was compiled as a debug build. @@ -381,10 +381,10 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q void entityScriptDetailsUpdated(); public: // not for public use, but I don't like how Qt strings this along with private friend functions - virtual ScriptValuePointer create(int type, const void* ptr); - virtual bool convert(const ScriptValuePointer& value, int type, void* ptr); + virtual ScriptValue create(int type, const void* ptr); + virtual bool convert(const ScriptValue& value, int type, void* ptr); virtual void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, - ScriptEngine::DemarshalFunction demarshalFunc, const ScriptValuePointer& prototype); + ScriptEngine::DemarshalFunction demarshalFunc, const ScriptValue& prototype); protected: // like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues @@ -408,8 +408,8 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q QPointer _manager; int _nextCustomType = 0; - ScriptValuePointer _nullValue; - ScriptValuePointer _undefinedValue; + ScriptValue _nullValue; + ScriptValue _undefinedValue; mutable ScriptContextQtPointer _currContext; std::atomic _isRunning { false }; diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp index c56f021f88f..ea3a4fe542e 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.cpp @@ -27,7 +27,7 @@ void ScriptValueIteratorQtWrapper::next() { _value.next(); } -ScriptValuePointer ScriptValueIteratorQtWrapper::value() const { +ScriptValue ScriptValueIteratorQtWrapper::value() const { QScriptValue result = _value.value(); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h index 7835e7cfae0..9250117df78 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h @@ -25,7 +25,7 @@ /// [QtScript] Implements ScriptValueIterator for QtScript and translates calls for QScriptValueIterator class ScriptValueIteratorQtWrapper : public ScriptValueIterator { public: // construction - inline ScriptValueIteratorQtWrapper(ScriptEngineQtScript* engine, const ScriptValuePointer& object) : + inline ScriptValueIteratorQtWrapper(ScriptEngineQtScript* engine, const ScriptValue& object) : _engine(engine), _value(ScriptValueQtWrapper::fullUnwrap(engine, object)) {} inline ScriptValueIteratorQtWrapper(ScriptEngineQtScript* engine, const QScriptValue& object) : _engine(engine), _value(object) {} @@ -35,7 +35,7 @@ class ScriptValueIteratorQtWrapper : public ScriptValueIterator { virtual bool hasNext() const; virtual QString name() const; virtual void next(); - virtual ScriptValuePointer value() const; + virtual ScriptValue value() const; private: // storage QPointer _engine; diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp index f0d1e4d22bc..768ec412466 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp @@ -13,73 +13,71 @@ #include "ScriptValueIteratorQtWrapper.h" -ScriptValueQtWrapper* ScriptValueQtWrapper::unwrap(ScriptValuePointer val) { - if (!val) { - return nullptr; - } +void ScriptValueQtWrapper::release() { + delete this; +} - return dynamic_cast(val.data()); +ScriptValueProxy* ScriptValueQtWrapper::copy() const { + return new ScriptValueQtWrapper(_engine, _value); } -QScriptValue ScriptValueQtWrapper::fullUnwrap(const ScriptValuePointer& value) const { - if (!value) { - return QScriptValue(); - } +ScriptValueQtWrapper* ScriptValueQtWrapper::unwrap(const ScriptValue& val) { + return dynamic_cast(val.ptr()); +} + +QScriptValue ScriptValueQtWrapper::fullUnwrap(const ScriptValue& value) const { ScriptValueQtWrapper* unwrapped = unwrap(value); if (unwrapped) { return unwrapped->toQtValue(); } - QVariant varValue = value->toVariant(); + QVariant varValue = value.toVariant(); return static_cast(_engine)->newVariant(varValue); } -QScriptValue ScriptValueQtWrapper::fullUnwrap(ScriptEngineQtScript* engine, const ScriptValuePointer& value) { - if (!value) { - return QScriptValue(); - } +QScriptValue ScriptValueQtWrapper::fullUnwrap(ScriptEngineQtScript* engine, const ScriptValue& value) { ScriptValueQtWrapper* unwrapped = unwrap(value); if (unwrapped) { return unwrapped->toQtValue(); } - QVariant varValue = value->toVariant(); + QVariant varValue = value.toVariant(); return static_cast(engine)->newVariant(varValue); } -ScriptValuePointer ScriptValueQtWrapper::call(const ScriptValuePointer& thisObject, const ScriptValueList& args) { +ScriptValue ScriptValueQtWrapper::call(const ScriptValue& thisObject, const ScriptValueList& args) { QScriptValue qThis = fullUnwrap(thisObject); QScriptValueList qArgs; for (ScriptValueList::const_iterator iter = args.begin(); iter != args.end(); ++iter) { qArgs.push_back(fullUnwrap(*iter)); } QScriptValue result = _value.call(qThis, qArgs); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } -ScriptValuePointer ScriptValueQtWrapper::call(const ScriptValuePointer& thisObject, const ScriptValuePointer& arguments) { +ScriptValue ScriptValueQtWrapper::call(const ScriptValue& thisObject, const ScriptValue& arguments) { QScriptValue qThis = fullUnwrap(thisObject); QScriptValue qArgs = fullUnwrap(arguments); QScriptValue result = _value.call(qThis, qArgs); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } -ScriptValuePointer ScriptValueQtWrapper::construct(const ScriptValueList& args) { +ScriptValue ScriptValueQtWrapper::construct(const ScriptValueList& args) { QScriptValueList qArgs; for (ScriptValueList::const_iterator iter = args.begin(); iter != args.end(); ++iter) { qArgs.push_back(fullUnwrap(*iter)); } QScriptValue result = _value.construct(qArgs); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } -ScriptValuePointer ScriptValueQtWrapper::construct(const ScriptValuePointer& arguments) { +ScriptValue ScriptValueQtWrapper::construct(const ScriptValue& arguments) { QScriptValue unwrapped = fullUnwrap(arguments); QScriptValue result = _value.construct(unwrapped); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } -ScriptValuePointer ScriptValueQtWrapper::data() const { +ScriptValue ScriptValueQtWrapper::data() const { QScriptValue result = _value.data(); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } ScriptEnginePointer ScriptValueQtWrapper::engine() const { @@ -89,43 +87,43 @@ ScriptEnginePointer ScriptValueQtWrapper::engine() const { return _engine->sharedFromThis(); } -ScriptValueIteratorPointer ScriptValueQtWrapper::newIterator() { +ScriptValueIteratorPointer ScriptValueQtWrapper::newIterator() const { return ScriptValueIteratorPointer(new ScriptValueIteratorQtWrapper(_engine, _value)); } -ScriptValuePointer ScriptValueQtWrapper::property(const QString& name, const ResolveFlags& mode) const { +ScriptValue ScriptValueQtWrapper::property(const QString& name, const ScriptValue::ResolveFlags& mode) const { QScriptValue result = _value.property(name, (QScriptValue::ResolveFlags)(int)mode); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } -ScriptValuePointer ScriptValueQtWrapper::property(quint32 arrayIndex, const ResolveFlags& mode) const { +ScriptValue ScriptValueQtWrapper::property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode) const { QScriptValue result = _value.property(arrayIndex, (QScriptValue::ResolveFlags)(int)mode); - return ScriptValuePointer(new ScriptValueQtWrapper(_engine, std::move(result))); + return ScriptValue(new ScriptValueQtWrapper(_engine, std::move(result))); } -void ScriptValueQtWrapper::setData(const ScriptValuePointer& value) { +void ScriptValueQtWrapper::setData(const ScriptValue& value) { QScriptValue unwrapped = fullUnwrap(value); _value.setData(unwrapped); } -void ScriptValueQtWrapper::setProperty(const QString& name, const ScriptValuePointer& value, const PropertyFlags& flags) { +void ScriptValueQtWrapper::setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { QScriptValue unwrapped = fullUnwrap(value); _value.setProperty(name, unwrapped, (QScriptValue::PropertyFlags)(int)flags); } -void ScriptValueQtWrapper::setProperty(quint32 arrayIndex, const ScriptValuePointer& value, const PropertyFlags& flags) { +void ScriptValueQtWrapper::setProperty(quint32 arrayIndex, const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { QScriptValue unwrapped = fullUnwrap(value); _value.setProperty(arrayIndex, unwrapped, (QScriptValue::PropertyFlags)(int)flags); } -void ScriptValueQtWrapper::setPrototype(const ScriptValuePointer& prototype) { +void ScriptValueQtWrapper::setPrototype(const ScriptValue& prototype) { ScriptValueQtWrapper* unwrappedPrototype = unwrap(prototype); if (unwrappedPrototype) { _value.setPrototype(unwrappedPrototype->toQtValue()); } } -bool ScriptValueQtWrapper::strictlyEquals(const ScriptValuePointer& other) const { +bool ScriptValueQtWrapper::strictlyEquals(const ScriptValue& other) const { ScriptValueQtWrapper* unwrappedOther = unwrap(other); return unwrappedOther ? _value.strictlyEquals(unwrappedOther->toQtValue()) : false; } @@ -166,51 +164,51 @@ QObject* ScriptValueQtWrapper::toQObject() const { return _value.toQObject(); } -bool ScriptValueQtWrapper::equalsInternal(const ScriptValuePointer& other) const { +bool ScriptValueQtWrapper::equals(const ScriptValue& other) const { ScriptValueQtWrapper* unwrappedOther = unwrap(other); return unwrappedOther ? _value.equals(unwrappedOther->toQtValue()) : false; } -bool ScriptValueQtWrapper::isArrayInternal() const { +bool ScriptValueQtWrapper::isArray() const { return _value.isArray(); } -bool ScriptValueQtWrapper::isBoolInternal() const { +bool ScriptValueQtWrapper::isBool() const { return _value.isBool(); } -bool ScriptValueQtWrapper::isErrorInternal() const { +bool ScriptValueQtWrapper::isError() const { return _value.isError(); } -bool ScriptValueQtWrapper::isFunctionInternal() const { +bool ScriptValueQtWrapper::isFunction() const { return _value.isFunction(); } -bool ScriptValueQtWrapper::isNumberInternal() const { +bool ScriptValueQtWrapper::isNumber() const { return _value.isNumber(); } -bool ScriptValueQtWrapper::isNullInternal() const { +bool ScriptValueQtWrapper::isNull() const { return _value.isNull(); } -bool ScriptValueQtWrapper::isObjectInternal() const { +bool ScriptValueQtWrapper::isObject() const { return _value.isObject(); } -bool ScriptValueQtWrapper::isStringInternal() const { +bool ScriptValueQtWrapper::isString() const { return _value.isString(); } -bool ScriptValueQtWrapper::isUndefinedInternal() const { +bool ScriptValueQtWrapper::isUndefined() const { return _value.isUndefined(); } -bool ScriptValueQtWrapper::isValidInternal() const { +bool ScriptValueQtWrapper::isValid() const { return _value.isValid(); } -bool ScriptValueQtWrapper::isVariantInternal() const { +bool ScriptValueQtWrapper::isVariant() const { return _value.isVariant(); } diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h index d7fa124a5aa..363bf71d057 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h @@ -24,37 +24,54 @@ #include "ScriptEngineQtScript.h" /// [QtScript] Implements ScriptValue for QtScript and translates calls for QScriptValue -class ScriptValueQtWrapper : public ScriptValue { +class ScriptValueQtWrapper : public ScriptValueProxy { public: // construction inline ScriptValueQtWrapper(ScriptEngineQtScript* engine, const QScriptValue& value) : _engine(engine), _value(value) {} inline ScriptValueQtWrapper(ScriptEngineQtScript* engine, QScriptValue&& value) : _engine(engine), _value(std::move(value)) {} - static ScriptValueQtWrapper* unwrap(ScriptValuePointer val); + static ScriptValueQtWrapper* unwrap(const ScriptValue& val); inline const QScriptValue& toQtValue() const { return _value; } - static QScriptValue fullUnwrap(ScriptEngineQtScript* engine, const ScriptValuePointer& value); + static QScriptValue fullUnwrap(ScriptEngineQtScript* engine, const ScriptValue& value); -public: // ScriptValue implementation - virtual ScriptValuePointer call(const ScriptValuePointer& thisObject = ScriptValuePointer(), - const ScriptValueList& args = ScriptValueList()); - virtual ScriptValuePointer call(const ScriptValuePointer& thisObject, const ScriptValuePointer& arguments); - virtual ScriptValuePointer construct(const ScriptValueList& args = ScriptValueList()); - virtual ScriptValuePointer construct(const ScriptValuePointer& arguments); - virtual ScriptValuePointer data() const; +public: + virtual void release(); + virtual ScriptValueProxy* copy() const; + +public: // ScriptValue implementation + virtual ScriptValue call(const ScriptValue& thisObject = ScriptValue(), const ScriptValueList& args = ScriptValueList()); + virtual ScriptValue call(const ScriptValue& thisObject, const ScriptValue& arguments); + virtual ScriptValue construct(const ScriptValueList& args = ScriptValueList()); + virtual ScriptValue construct(const ScriptValue& arguments); + virtual ScriptValue data() const; virtual ScriptEnginePointer engine() const; - virtual ScriptValueIteratorPointer newIterator(); - virtual ScriptValuePointer property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const; - virtual ScriptValuePointer property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const; - virtual void setData(const ScriptValuePointer& val); + virtual ScriptValueIteratorPointer newIterator() const; + virtual ScriptValue property(const QString& name, + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const; + virtual ScriptValue property(quint32 arrayIndex, + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const; + virtual void setData(const ScriptValue& val); virtual void setProperty(const QString& name, - const ScriptValuePointer& value, - const PropertyFlags& flags = KeepExistingFlags); + const ScriptValue& value, + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags); virtual void setProperty(quint32 arrayIndex, - const ScriptValuePointer& value, - const PropertyFlags& flags = KeepExistingFlags); - virtual void setPrototype(const ScriptValuePointer& prototype); - virtual bool strictlyEquals(const ScriptValuePointer& other) const; + const ScriptValue& value, + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags); + virtual void setPrototype(const ScriptValue& prototype); + virtual bool strictlyEquals(const ScriptValue& other) const; + virtual bool equals(const ScriptValue& other) const; + virtual bool isArray() const; + virtual bool isBool() const; + virtual bool isError() const; + virtual bool isFunction() const; + virtual bool isNumber() const; + virtual bool isNull() const; + virtual bool isObject() const; + virtual bool isString() const; + virtual bool isUndefined() const; + virtual bool isValid() const; + virtual bool isVariant() const; virtual bool toBool() const; virtual qint32 toInt32() const; virtual double toInteger() const; @@ -65,22 +82,8 @@ class ScriptValueQtWrapper : public ScriptValue { virtual QVariant toVariant() const; virtual QObject* toQObject() const; -protected: // ScriptValue implementation - virtual bool equalsInternal(const ScriptValuePointer& other) const; - virtual bool isArrayInternal() const; - virtual bool isBoolInternal() const; - virtual bool isErrorInternal() const; - virtual bool isFunctionInternal() const; - virtual bool isNumberInternal() const; - virtual bool isNullInternal() const; - virtual bool isObjectInternal() const; - virtual bool isStringInternal() const; - virtual bool isUndefinedInternal() const; - virtual bool isValidInternal() const; - virtual bool isVariantInternal() const; - private: // helper functions - QScriptValue fullUnwrap(const ScriptValuePointer& value) const; + QScriptValue fullUnwrap(const ScriptValue& value) const; private: // storage QPointer _engine; diff --git a/libraries/ui/src/QmlFragmentClass.cpp b/libraries/ui/src/QmlFragmentClass.cpp index 163d5e2ca70..b0fe2789605 100644 --- a/libraries/ui/src/QmlFragmentClass.cpp +++ b/libraries/ui/src/QmlFragmentClass.cpp @@ -17,15 +17,15 @@ #include std::mutex QmlFragmentClass::_mutex; -std::map QmlFragmentClass::_fragments; +std::map QmlFragmentClass::_fragments; QmlFragmentClass::QmlFragmentClass(bool restricted, QString id) : QmlWindowClass(restricted), qml(id) { } // Method called by Qt scripts to create a new bottom menu bar in Android -ScriptValuePointer QmlFragmentClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { +ScriptValue QmlFragmentClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { #ifndef DISABLE_QML std::lock_guard guard(_mutex); - auto qml = context->argument(0)->toVariant().toMap().value("qml"); + auto qml = context->argument(0).toVariant().toMap().value("qml"); if (qml.isValid()) { // look up tabletId in the map. auto iter = _fragments.find(qml.toString()); @@ -35,7 +35,7 @@ ScriptValuePointer QmlFragmentClass::internal_constructor(ScriptContext* context } } else { qWarning() << "QmlFragmentClass could not build instance " << qml; - return ScriptValuePointer(); + return ScriptValue(); } auto properties = parseArguments(context); @@ -49,11 +49,11 @@ ScriptValuePointer QmlFragmentClass::internal_constructor(ScriptContext* context } auto manager = engine->manager(); connect(manager, &ScriptManager::destroyed, retVal, &QmlWindowClass::deleteLater); - ScriptValuePointer scriptObject = engine->newQObject(retVal); + ScriptValue scriptObject = engine->newQObject(retVal); _fragments[qml.toString()] = scriptObject; return scriptObject; #else - return ScriptValuePointer(); + return ScriptValue(); #endif } diff --git a/libraries/ui/src/QmlFragmentClass.h b/libraries/ui/src/QmlFragmentClass.h index 35399782ea5..9c04fe62633 100644 --- a/libraries/ui/src/QmlFragmentClass.h +++ b/libraries/ui/src/QmlFragmentClass.h @@ -10,24 +10,22 @@ #define hifi_ui_QmlFragmentClass_h #include "QmlWindowClass.h" -#include +#include class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class QmlFragmentClass : public QmlWindowClass { Q_OBJECT private: - static ScriptValuePointer internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); + static ScriptValue internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); public: - static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine) { + static ScriptValue constructor(ScriptContext* context, ScriptEngine* engine) { return internal_constructor(context, engine, false); } - static ScriptValuePointer restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ + static ScriptValue restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ return internal_constructor(context, engine, true); } @@ -52,7 +50,7 @@ public slots: QString qmlSource() const override { return qml; } static std::mutex _mutex; - static std::map _fragments; + static std::map _fragments; private: QString qml; diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index e86355a3442..9fc5ccdf78b 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -20,7 +20,7 @@ static const char* const URL_PROPERTY = "source"; static const char* const SCRIPT_PROPERTY = "scriptUrl"; // Method called by Qt scripts to create a new web window in the overlay -ScriptValuePointer QmlWebWindowClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { +ScriptValue QmlWebWindowClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { auto properties = parseArguments(context); QmlWebWindowClass* retVal = new QmlWebWindowClass(restricted); Q_ASSERT(retVal); diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index da5b73c81d9..20dadd98bbd 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -13,10 +13,10 @@ #include "QmlWindowClass.h" +#include + class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * A OverlayWebWindow displays an HTML window inside Interface. @@ -149,15 +149,15 @@ class QmlWebWindowClass : public QmlWindowClass { Q_PROPERTY(QString url READ getURL CONSTANT) private: - static ScriptValuePointer internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); + static ScriptValue internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); public: QmlWebWindowClass(bool restricted) : QmlWindowClass(restricted) {} - static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine) { + static ScriptValue constructor(ScriptContext* context, ScriptEngine* engine) { return internal_constructor(context, engine, false); } - static ScriptValuePointer restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ + static ScriptValue restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ return internal_constructor(context, engine, true); } diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index c0f2e9a51e8..f38dd7723d5 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -43,20 +43,20 @@ QVariantMap QmlWindowClass::parseArguments(ScriptContext* context) { const auto argumentCount = context->argumentCount(); QVariantMap properties; if (argumentCount > 1) { - if (!context->argument(0)->isUndefined()) { - properties[TITLE_PROPERTY] = context->argument(0)->toString(); + if (!context->argument(0).isUndefined()) { + properties[TITLE_PROPERTY] = context->argument(0).toString(); } - if (!context->argument(1)->isUndefined()) { - properties[SOURCE_PROPERTY] = context->argument(1)->toString(); + if (!context->argument(1).isUndefined()) { + properties[SOURCE_PROPERTY] = context->argument(1).toString(); } - if (context->argument(2)->isNumber()) { - properties[WIDTH_PROPERTY] = context->argument(2)->toInt32(); + if (context->argument(2).isNumber()) { + properties[WIDTH_PROPERTY] = context->argument(2).toInt32(); } - if (context->argument(3)->isNumber()) { - properties[HEIGHT_PROPERTY] = context->argument(3)->toInt32(); + if (context->argument(3).isNumber()) { + properties[HEIGHT_PROPERTY] = context->argument(3).toInt32(); } } else { - properties = context->argument(0)->toVariant().toMap(); + properties = context->argument(0).toVariant().toMap(); } QUrl url { properties[SOURCE_PROPERTY].toString() }; @@ -72,7 +72,7 @@ QVariantMap QmlWindowClass::parseArguments(ScriptContext* context) { // Method called by Qt scripts to create a new web window in the overlay -ScriptValuePointer QmlWindowClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { +ScriptValue QmlWindowClass::internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted) { auto properties = parseArguments(context); QmlWindowClass* retVal = new QmlWindowClass(restricted); Q_ASSERT(retVal); diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h index da44aed9fae..5d1111bd5ab 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -11,15 +11,13 @@ #include #include -#include #include #include +#include class ScriptContext; class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; /*@jsdoc * A OverlayWindow displays a QML window inside Interface. @@ -55,13 +53,13 @@ class QmlWindowClass : public QObject { Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) private: - static ScriptValuePointer internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); + static ScriptValue internal_constructor(ScriptContext* context, ScriptEngine* engine, bool restricted); public: - static ScriptValuePointer constructor(ScriptContext* context, ScriptEngine* engine) { + static ScriptValue constructor(ScriptContext* context, ScriptEngine* engine) { return internal_constructor(context, engine, false); } - static ScriptValuePointer restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ + static ScriptValue restricted_constructor(ScriptContext* context, ScriptEngine* engine ){ return internal_constructor(context, engine, true); } @@ -348,7 +346,7 @@ protected slots: protected: static QVariantMap parseArguments(ScriptContext* context); - static ScriptValuePointer internalConstructor(ScriptContext* context, ScriptEngine* engine, + static ScriptValue internalConstructor(ScriptContext* context, ScriptEngine* engine, std::function function); virtual QString qmlSource() const { return "QmlWindow.qml"; } diff --git a/libraries/ui/src/ui/QmlWrapper.h b/libraries/ui/src/ui/QmlWrapper.h index b5150f440c6..84873472b96 100644 --- a/libraries/ui/src/ui/QmlWrapper.h +++ b/libraries/ui/src/ui/QmlWrapper.h @@ -11,11 +11,10 @@ #include #include -#include + +#include class ScriptEngine; -class ScriptValue; -using ScriptValuePointer = QSharedPointer; class QmlWrapper : public QObject { Q_OBJECT @@ -32,7 +31,7 @@ class QmlWrapper : public QObject { }; template -ScriptValuePointer wrapperToScriptValue(ScriptEngine* engine, T* const &in) { +ScriptValue wrapperToScriptValue(ScriptEngine* engine, T* const &in) { if (!in) { return engine->undefinedValue(); } @@ -40,8 +39,8 @@ ScriptValuePointer wrapperToScriptValue(ScriptEngine* engine, T* const &in) { } template -void wrapperFromScriptValue(const ScriptValuePointer& value, T* &out) { - out = qobject_cast(value->toQObject()); +void wrapperFromScriptValue(const ScriptValue& value, T* &out) { + out = qobject_cast(value.toQObject()); } #endif \ No newline at end of file diff --git a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp index e23023e137a..c2e908f8a44 100644 --- a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp +++ b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp @@ -16,26 +16,26 @@ #include #include "../OffscreenUi.h" -ScriptValuePointer toolbarToScriptValue(ScriptEngine* engine, ToolbarProxy* const &in) { +ScriptValue toolbarToScriptValue(ScriptEngine* engine, ToolbarProxy* const &in) { if (!in) { return engine->undefinedValue(); } return engine->newQObject(in, ScriptEngine::QtOwnership); } -void toolbarFromScriptValue(const ScriptValuePointer& value, ToolbarProxy* &out) { - out = qobject_cast(value->toQObject()); +void toolbarFromScriptValue(const ScriptValue& value, ToolbarProxy* &out) { + out = qobject_cast(value.toQObject()); } -ScriptValuePointer toolbarButtonToScriptValue(ScriptEngine* engine, ToolbarButtonProxy* const &in) { +ScriptValue toolbarButtonToScriptValue(ScriptEngine* engine, ToolbarButtonProxy* const &in) { if (!in) { return engine->undefinedValue(); } return engine->newQObject(in, ScriptEngine::QtOwnership); } -void toolbarButtonFromScriptValue(const ScriptValuePointer& value, ToolbarButtonProxy* &out) { - out = qobject_cast(value->toQObject()); +void toolbarButtonFromScriptValue(const ScriptValue& value, ToolbarButtonProxy* &out) { + out = qobject_cast(value.toQObject()); } diff --git a/plugins/JSAPIExample/src/JSAPIExample.cpp b/plugins/JSAPIExample/src/JSAPIExample.cpp index d2cddcc3b1f..67a0a9bc77d 100644 --- a/plugins/JSAPIExample/src/JSAPIExample.cpp +++ b/plugins/JSAPIExample/src/JSAPIExample.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -64,7 +65,7 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { qCWarning(logger) << "registering w/ScriptInitializerMixin..." << scriptInit.data(); scriptInit->registerScriptInitializer([this](ScriptEngine* engine) { auto value = engine->newQObject(this, ScriptEngine::QtOwnership); - engine->globalObject()->setProperty(objectName(), value); + engine->globalObject().setProperty(objectName(), value); // qCDebug(logger) << "setGlobalInstance" << objectName() << engine->property("fileName"); }); // qCInfo(logger) << "plugin loaded" << qApp << toString() << QThread::currentThread(); @@ -72,7 +73,7 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { // NOTES: everything within the "public slots:" section below will be available from JS via overall plugin QObject // also, to demonstrate future-proofing JS API code, QVariant's are used throughout most of these examples -- - // which still makes them very Qt-specific, but avoids depending directly on deprecated ScriptValuePointer APIs. + // which still makes them very Qt-specific, but avoids depending directly on deprecated ScriptValue APIs. // (as such this plugin class and its methods remain forward-compatible with other engines like QML's QJSEngine) public slots: @@ -159,14 +160,14 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME { * print("all example::* keys", settings.allKeys()); * settings = null; // optional best pratice; allows the object to be reclaimed ASAP by the JS garbage collector */ - ScriptValuePointer getScopedSettings(const QString& scope) { + ScriptValue getScopedSettings(const QString& scope) { auto engine = Scriptable::engine(); if (!engine) { - return ScriptValuePointer(); + return ScriptValue(); } auto manager = engine->manager(); if (!manager) { - return ScriptValuePointer(); + return ScriptValue(); } QString error; auto cppValue = createScopedSettings(scope, manager, error); diff --git a/plugins/hifiNeuron/CMakeLists.txt b/plugins/hifiNeuron/CMakeLists.txt index ad4f78698cd..25fd8ff2e54 100644 --- a/plugins/hifiNeuron/CMakeLists.txt +++ b/plugins/hifiNeuron/CMakeLists.txt @@ -11,6 +11,7 @@ if (WIN32) set(TARGET_NAME hifiNeuron) setup_hifi_plugin(Qml) link_hifi_libraries(shared controllers qml ui plugins input-plugins) + include_hifi_library_headers(script-engine) target_neuron() endif() diff --git a/plugins/hifiOsc/CMakeLists.txt b/plugins/hifiOsc/CMakeLists.txt index cb8b437ab6a..78514f5888b 100644 --- a/plugins/hifiOsc/CMakeLists.txt +++ b/plugins/hifiOsc/CMakeLists.txt @@ -9,6 +9,7 @@ set(TARGET_NAME hifiOsc) setup_hifi_plugin(Qml) link_hifi_libraries(shared controllers ui plugins input-plugins display-plugins) +include_hifi_library_headers(script-engine) target_liblo() diff --git a/plugins/hifiSdl2/CMakeLists.txt b/plugins/hifiSdl2/CMakeLists.txt index 47d382681fd..16ce6f51b4a 100644 --- a/plugins/hifiSdl2/CMakeLists.txt +++ b/plugins/hifiSdl2/CMakeLists.txt @@ -17,5 +17,6 @@ if (NOT APPLE) endif() setup_hifi_plugin(Qml) link_hifi_libraries(shared controllers ui plugins input-plugins) + include_hifi_library_headers(script-engine) target_sdl2() endif() diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 6ddc75e1e55..2eb7fb48250 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -22,6 +22,7 @@ if (WIN32 AND (NOT USE_GLES)) ${PLATFORM_GL_BACKEND} ) include_hifi_library_headers(octree) + include_hifi_library_headers(script-engine) add_dependency_external_projects(LibOVR) find_package(LibOVR REQUIRED) From e6117d2cdb613eb2c67b61dbf70918feb5258cf5 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Fri, 3 Sep 2021 14:37:10 -0700 Subject: [PATCH 11/34] changes in response to build log on other compilers --- libraries/script-engine/src/ScriptEngine.h | 7 ++ .../script-engine/src/ScriptEngineCast.h | 2 +- libraries/script-engine/src/ScriptValue.h | 14 +-- .../src/qtscript/ScriptContextQtWrapper.h | 28 +++--- .../src/qtscript/ScriptEngineQtScript.h | 90 +++++++++---------- .../src/qtscript/ScriptProgramQtWrapper.h | 14 +-- .../qtscript/ScriptValueIteratorQtWrapper.h | 10 +-- .../src/qtscript/ScriptValueQtWrapper.h | 75 ++++++++-------- 8 files changed, 125 insertions(+), 115 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index b1fb6d4cd5c..dd8d539f216 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -36,6 +36,13 @@ using ScriptProgramPointer = QSharedPointer; Q_DECLARE_METATYPE(ScriptEnginePointer); +template +inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const T& t); + +template +inline T scriptvalue_cast(const ScriptValue& value); + + /// [ScriptInterface] Provides an engine-independent interface for QScriptEngine class ScriptEngine { public: diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h index b378302fe2b..475c869584c 100644 --- a/libraries/script-engine/src/ScriptEngineCast.h +++ b/libraries/script-engine/src/ScriptEngineCast.h @@ -41,7 +41,7 @@ inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const QV } template -T scriptvalue_cast(const ScriptValue& value) { +inline T scriptvalue_cast(const ScriptValue& value) { T t; const int id = qMetaTypeId(); diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h index e2c608b8fcc..afb578a676c 100644 --- a/libraries/script-engine/src/ScriptValue.h +++ b/libraries/script-engine/src/ScriptValue.h @@ -89,10 +89,10 @@ class ScriptValue { inline void setProperty(quint32 arrayIndex, const ScriptValue& value, const PropertyFlags& flags = KeepExistingFlags); - template + template inline void setProperty(const QString& name, const TYP& value, const PropertyFlags& flags = KeepExistingFlags); - template + template inline void setProperty(quint32 arrayIndex, const TYP& value, const PropertyFlags& flags = KeepExistingFlags); inline void setPrototype(const ScriptValue& prototype); @@ -165,14 +165,16 @@ class ScriptValueProxy { virtual QObject* toQObject() const = 0; }; -template +// the second template parameter is used to defer evaluation of calls to the engine until ScriptEngine isn't forward-declared +template void ScriptValue::setProperty(const QString& name, const TYP& value, const PropertyFlags& flags) { - setProperty(name, engine()->newValue(value), flags); + setProperty(name, static_cast(engine())->newValue(value), flags); } -template +// the second template parameter is used to defer evaluation of calls to the engine until ScriptEngine isn't forward-declared +template void ScriptValue::setProperty(quint32 arrayIndex, const TYP& value, const PropertyFlags& flags) { - setProperty(arrayIndex, engine()->newValue(value), flags); + setProperty(arrayIndex, static_cast(engine())->newValue(value), flags); } ScriptValue::ScriptValue(const ScriptValue& src) : _proxy(src.ptr()->copy()) { diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h index db542799c83..f93a59e7bce 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h @@ -32,16 +32,16 @@ class ScriptContextQtWrapper : public ScriptContext { inline QScriptContext* toQtValue() const { return _context; } public: // ScriptContext implementation - virtual int argumentCount() const; - virtual ScriptValue argument(int index) const; - virtual QStringList backtrace() const; - virtual ScriptValue callee() const; - virtual ScriptEnginePointer engine() const; - virtual ScriptFunctionContextPointer functionContext() const; - virtual ScriptContextPointer parentContext() const; - virtual ScriptValue thisObject() const; - virtual ScriptValue throwError(const QString& text); - virtual ScriptValue throwValue(const ScriptValue& value); + virtual int argumentCount() const override; + virtual ScriptValue argument(int index) const override; + virtual QStringList backtrace() const override; + virtual ScriptValue callee() const override; + virtual ScriptEnginePointer engine() const override; + virtual ScriptFunctionContextPointer functionContext() const override; + virtual ScriptContextPointer parentContext() const override; + virtual ScriptValue thisObject() const override; + virtual ScriptValue throwError(const QString& text) override; + virtual ScriptValue throwValue(const ScriptValue& value) override; private: // storage QScriptContext* _context; @@ -53,10 +53,10 @@ class ScriptFunctionContextQtWrapper : public ScriptFunctionContext { inline ScriptFunctionContextQtWrapper(QScriptContext* context) : _value(context) {} public: // ScriptFunctionContext implementation - virtual QString fileName() const; - virtual QString functionName() const; - virtual FunctionType functionType() const; - virtual int lineNumber() const; + virtual QString fileName() const override; + virtual QString functionName() const override; + virtual FunctionType functionType() const override; + virtual int lineNumber() const override; private: // storage QScriptContextInfo _value; diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index ada261ec3c8..1ba854ced19 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -45,55 +45,55 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q Q_OBJECT public: // ScriptEngine implementation - virtual void abortEvaluation(); - virtual void clearExceptions(); - virtual ScriptValue cloneUncaughtException(const QString& detail = QString()); - virtual ScriptContext* currentContext() const; - //virtual ScriptValue evaluate(const QString& program, const QString& fileName = QString()); - //virtual ScriptValue evaluate(const ScriptProgramPointer &program); - //virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program); - virtual ScriptValue globalObject() const; - virtual bool hasUncaughtException() const; - virtual bool isEvaluating() const; - virtual ScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1); - virtual ScriptValue makeError(const ScriptValue& other, const QString& type = "Error"); - virtual ScriptManager* manager() const; + virtual void abortEvaluation() override; + virtual void clearExceptions() override; + virtual ScriptValue cloneUncaughtException(const QString& detail = QString()) override; + virtual ScriptContext* currentContext() const override; + //virtual ScriptValue evaluate(const QString& program, const QString& fileName = QString()) override; + //virtual ScriptValue evaluate(const ScriptProgramPointer &program) override; + //virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) override; + virtual ScriptValue globalObject() const override; + virtual bool hasUncaughtException() const override; + virtual bool isEvaluating() const override; + virtual ScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1) override; + virtual ScriptValue makeError(const ScriptValue& other, const QString& type = "Error") override; + virtual ScriptManager* manager() const override; // if there is a pending exception and we are at the top level (non-recursive) stack frame, this emits and resets it - virtual bool maybeEmitUncaughtException(const QString& debugHint = QString()); + virtual bool maybeEmitUncaughtException(const QString& debugHint = QString()) override; - virtual ScriptValue newArray(uint length = 0); - virtual ScriptValue newArrayBuffer(const QByteArray& message); - virtual ScriptValue newFunction(ScriptEngine::FunctionSignature fun, int length = 0); - virtual ScriptValue newObject(); - virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName); + virtual ScriptValue newArray(uint length = 0) override; + virtual ScriptValue newArrayBuffer(const QByteArray& message) override; + virtual ScriptValue newFunction(ScriptEngine::FunctionSignature fun, int length = 0) override; + virtual ScriptValue newObject() override; + virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName) override; virtual ScriptValue newQObject(QObject *object, ScriptEngine::ValueOwnership ownership = ScriptEngine::QtOwnership, - const ScriptEngine::QObjectWrapOptions &options = ScriptEngine::QObjectWrapOptions()); - virtual ScriptValue newValue(bool value); - virtual ScriptValue newValue(int value); - virtual ScriptValue newValue(uint value); - virtual ScriptValue newValue(double value); - virtual ScriptValue newValue(const QString& value); - virtual ScriptValue newValue(const QLatin1String& value); - virtual ScriptValue newValue(const char* value); - virtual ScriptValue newVariant(const QVariant& value); - virtual ScriptValue nullValue(); - virtual bool raiseException(const ScriptValue& exception); - //virtual void registerEnum(const QString& enumName, QMetaEnum newEnum); - //Q_INVOKABLE virtual void registerFunction(const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); - //Q_INVOKABLE virtual void registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); - //Q_INVOKABLE virtual void registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent = QString("")); - //virtual void registerGlobalObject(const QString& name, QObject* object); - virtual void setDefaultPrototype(int metaTypeId, const ScriptValue& prototype); - virtual void setObjectName(const QString& name); - virtual bool setProperty(const char* name, const QVariant& value); - virtual void setProcessEventsInterval(int interval); - virtual QThread* thread() const; - virtual void setThread(QThread* thread); - virtual ScriptValue undefinedValue(); - virtual ScriptValue uncaughtException() const; - virtual QStringList uncaughtExceptionBacktrace() const; - virtual int uncaughtExceptionLineNumber() const; + const ScriptEngine::QObjectWrapOptions& options = ScriptEngine::QObjectWrapOptions()) override; + virtual ScriptValue newValue(bool value) override; + virtual ScriptValue newValue(int value) override; + virtual ScriptValue newValue(uint value) override; + virtual ScriptValue newValue(double value) override; + virtual ScriptValue newValue(const QString& value) override; + virtual ScriptValue newValue(const QLatin1String& value) override; + virtual ScriptValue newValue(const char* value) override; + virtual ScriptValue newVariant(const QVariant& value) override; + virtual ScriptValue nullValue() override; + virtual bool raiseException(const ScriptValue& exception) override; + //virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) override; + //Q_INVOKABLE virtual void registerFunction(const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1) override; + //Q_INVOKABLE virtual void registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1) override; + //Q_INVOKABLE virtual void registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent = QString("")) override; + //virtual void registerGlobalObject(const QString& name, QObject* object) override; + virtual void setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) override; + virtual void setObjectName(const QString& name) override; + virtual bool setProperty(const char* name, const QVariant& value) override; + virtual void setProcessEventsInterval(int interval) override; + virtual QThread* thread() const override; + virtual void setThread(QThread* thread) override; + virtual ScriptValue undefinedValue() override; + virtual ScriptValue uncaughtException() const override; + virtual QStringList uncaughtExceptionBacktrace() const override; + virtual int uncaughtExceptionLineNumber() const override; // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways inline bool IS_THREADSAFE_INVOCATION(const QString& method) { return ScriptEngine::IS_THREADSAFE_INVOCATION(method); } diff --git a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h index ddd477b90b9..cfd7982a8a4 100644 --- a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h @@ -32,9 +32,9 @@ class ScriptProgramQtWrapper : public ScriptProgram { inline const QScriptProgram& toQtValue() const { return _value; } public: // ScriptProgram implementation - virtual ScriptSyntaxCheckResultPointer checkSyntax() const; - virtual QString fileName() const; - virtual QString sourceCode() const; + virtual ScriptSyntaxCheckResultPointer checkSyntax() const override; + virtual QString fileName() const override; + virtual QString sourceCode() const override; private: // storage QPointer _engine; @@ -47,10 +47,10 @@ class ScriptSyntaxCheckResultQtWrapper : public ScriptSyntaxCheckResult { _value(std::move(value)) {} public: // ScriptSyntaxCheckResult implementation - virtual int errorColumnNumber() const; - virtual int errorLineNumber() const; - virtual QString errorMessage() const; - virtual State state() const; + virtual int errorColumnNumber() const override; + virtual int errorLineNumber() const override; + virtual QString errorMessage() const override; + virtual State state() const override; private: // storage QScriptSyntaxCheckResult _value; diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h index 9250117df78..54d3bd6116c 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h @@ -31,11 +31,11 @@ class ScriptValueIteratorQtWrapper : public ScriptValueIterator { _engine(engine), _value(object) {} public: // ScriptValueIterator implementation - virtual ScriptValue::PropertyFlags flags() const; - virtual bool hasNext() const; - virtual QString name() const; - virtual void next(); - virtual ScriptValue value() const; + virtual ScriptValue::PropertyFlags flags() const override; + virtual bool hasNext() const override; + virtual QString name() const override; + virtual void next() override; + virtual ScriptValue value() const override; private: // storage QPointer _engine; diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h index 363bf71d057..236c773633a 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h @@ -35,52 +35,53 @@ class ScriptValueQtWrapper : public ScriptValueProxy { static QScriptValue fullUnwrap(ScriptEngineQtScript* engine, const ScriptValue& value); public: - virtual void release(); - virtual ScriptValueProxy* copy() const; + virtual void release() override; + virtual ScriptValueProxy* copy() const override; public: // ScriptValue implementation - virtual ScriptValue call(const ScriptValue& thisObject = ScriptValue(), const ScriptValueList& args = ScriptValueList()); - virtual ScriptValue call(const ScriptValue& thisObject, const ScriptValue& arguments); - virtual ScriptValue construct(const ScriptValueList& args = ScriptValueList()); - virtual ScriptValue construct(const ScriptValue& arguments); - virtual ScriptValue data() const; - virtual ScriptEnginePointer engine() const; - virtual ScriptValueIteratorPointer newIterator() const; + virtual ScriptValue call(const ScriptValue& thisObject = ScriptValue(), + const ScriptValueList& args = ScriptValueList()) override; + virtual ScriptValue call(const ScriptValue& thisObject, const ScriptValue& arguments) override; + virtual ScriptValue construct(const ScriptValueList& args = ScriptValueList()) override; + virtual ScriptValue construct(const ScriptValue& arguments) override; + virtual ScriptValue data() const override; + virtual ScriptEnginePointer engine() const override; + virtual ScriptValueIteratorPointer newIterator() const override; virtual ScriptValue property(const QString& name, - const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const; + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; virtual ScriptValue property(quint32 arrayIndex, - const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const; - virtual void setData(const ScriptValue& val); + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; + virtual void setData(const ScriptValue& val) override; virtual void setProperty(const QString& name, const ScriptValue& value, - const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags); + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) override; virtual void setProperty(quint32 arrayIndex, const ScriptValue& value, - const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags); - virtual void setPrototype(const ScriptValue& prototype); - virtual bool strictlyEquals(const ScriptValue& other) const; + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) override; + virtual void setPrototype(const ScriptValue& prototype) override; + virtual bool strictlyEquals(const ScriptValue& other) const override; - virtual bool equals(const ScriptValue& other) const; - virtual bool isArray() const; - virtual bool isBool() const; - virtual bool isError() const; - virtual bool isFunction() const; - virtual bool isNumber() const; - virtual bool isNull() const; - virtual bool isObject() const; - virtual bool isString() const; - virtual bool isUndefined() const; - virtual bool isValid() const; - virtual bool isVariant() const; - virtual bool toBool() const; - virtual qint32 toInt32() const; - virtual double toInteger() const; - virtual double toNumber() const; - virtual QString toString() const; - virtual quint16 toUInt16() const; - virtual quint32 toUInt32() const; - virtual QVariant toVariant() const; - virtual QObject* toQObject() const; + virtual bool equals(const ScriptValue& other) const override; + virtual bool isArray() const override; + virtual bool isBool() const override; + virtual bool isError() const override; + virtual bool isFunction() const override; + virtual bool isNumber() const override; + virtual bool isNull() const override; + virtual bool isObject() const override; + virtual bool isString() const override; + virtual bool isUndefined() const override; + virtual bool isValid() const override; + virtual bool isVariant() const override; + virtual bool toBool() const override; + virtual qint32 toInt32() const override; + virtual double toInteger() const override; + virtual double toNumber() const override; + virtual QString toString() const override; + virtual quint16 toUInt16() const override; + virtual quint32 toUInt32() const override; + virtual QVariant toVariant() const override; + virtual QObject* toQObject() const override; private: // helper functions QScriptValue fullUnwrap(const ScriptValue& value) const; From 3a24305f7d55253da9d01c26b5a101be619bdd1f Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Fri, 3 Sep 2021 16:48:44 -0700 Subject: [PATCH 12/34] more changes in response to build log on other compilers --- libraries/script-engine/src/ScriptValue.cpp | 74 +++++++++---------- .../src/qtscript/ScriptEngineQtScript.h | 34 ++++++--- libraries/ui/src/ui/OffscreenQmlSurface.h | 4 +- libraries/ui/src/ui/QmlWrapper.h | 1 + 4 files changed, 63 insertions(+), 50 deletions(-) diff --git a/libraries/script-engine/src/ScriptValue.cpp b/libraries/script-engine/src/ScriptValue.cpp index 344d9a6393e..83f8e6b50ab 100644 --- a/libraries/script-engine/src/ScriptValue.cpp +++ b/libraries/script-engine/src/ScriptValue.cpp @@ -16,52 +16,52 @@ class ScriptValueProxyNull : public ScriptValueProxy { public: - virtual void release(); - virtual ScriptValueProxy* copy() const; + virtual void release() override; + virtual ScriptValueProxy* copy() const override; public: - virtual ScriptValue call(const ScriptValue& thisObject = ScriptValue(), const ScriptValueList& args = ScriptValueList()); - virtual ScriptValue call(const ScriptValue& thisObject, const ScriptValue& arguments); - virtual ScriptValue construct(const ScriptValueList& args = ScriptValueList()); - virtual ScriptValue construct(const ScriptValue& arguments); - virtual ScriptValue data() const; - virtual ScriptEnginePointer engine() const; - virtual bool equals(const ScriptValue& other) const; - virtual bool isArray() const; - virtual bool isBool() const; - virtual bool isError() const; - virtual bool isFunction() const; - virtual bool isNumber() const; - virtual bool isNull() const; - virtual bool isObject() const; - virtual bool isString() const; - virtual bool isUndefined() const; - virtual bool isValid() const; - virtual bool isVariant() const; - virtual ScriptValueIteratorPointer newIterator() const; + virtual ScriptValue call(const ScriptValue& thisObject = ScriptValue(), const ScriptValueList& args = ScriptValueList()) override; + virtual ScriptValue call(const ScriptValue& thisObject, const ScriptValue& arguments) override; + virtual ScriptValue construct(const ScriptValueList& args = ScriptValueList()) override; + virtual ScriptValue construct(const ScriptValue& arguments) override; + virtual ScriptValue data() const override; + virtual ScriptEnginePointer engine() const override; + virtual bool equals(const ScriptValue& other) const override; + virtual bool isArray() const override; + virtual bool isBool() const override; + virtual bool isError() const override; + virtual bool isFunction() const override; + virtual bool isNumber() const override; + virtual bool isNull() const override; + virtual bool isObject() const override; + virtual bool isString() const override; + virtual bool isUndefined() const override; + virtual bool isValid() const override; + virtual bool isVariant() const override; + virtual ScriptValueIteratorPointer newIterator() const override; virtual ScriptValue property(const QString& name, - const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const; + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; virtual ScriptValue property(quint32 arrayIndex, - const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const; + const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; virtual void setData(const ScriptValue& val); virtual void setProperty(const QString& name, const ScriptValue& value, - const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags); + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) override; virtual void setProperty(quint32 arrayIndex, const ScriptValue& value, - const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags); - virtual void setPrototype(const ScriptValue& prototype); - virtual bool strictlyEquals(const ScriptValue& other) const; - - virtual bool toBool() const; - virtual qint32 toInt32() const; - virtual double toInteger() const; - virtual double toNumber() const; - virtual QString toString() const; - virtual quint16 toUInt16() const; - virtual quint32 toUInt32() const; - virtual QVariant toVariant() const; - virtual QObject* toQObject() const; + const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) override; + virtual void setPrototype(const ScriptValue& prototype) override; + virtual bool strictlyEquals(const ScriptValue& other) const override; + + virtual bool toBool() const override; + virtual qint32 toInt32() const override; + virtual double toInteger() const override; + virtual double toNumber() const override; + virtual QString toString() const override; + virtual quint16 toUInt16() const override; + virtual quint32 toUInt32() const override; + virtual QVariant toVariant() const override; + virtual QObject* toQObject() const override; }; static ScriptValueProxyNull SCRIPT_VALUE_NULL; diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 1ba854ced19..31a8f0cade5 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -130,7 +130,7 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q * @deprecated This function is deprecated and will be removed. */ /// registers a global object by name - Q_INVOKABLE virtual void registerGlobalObject(const QString& name, QObject* object); + Q_INVOKABLE virtual void registerGlobalObject(const QString& name, QObject* object) override; /*@jsdoc * @function Script.registerGetterSetter @@ -144,7 +144,10 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q Q_INVOKABLE void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, const QString& parent = QString("")); - Q_INVOKABLE virtual void registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent = QString("")); + Q_INVOKABLE virtual void registerGetterSetter(const QString& name, + ScriptEngine::FunctionSignature getter, + ScriptEngine::FunctionSignature setter, + const QString& parent = QString("")) override; /*@jsdoc * @function Script.registerFunction @@ -157,7 +160,9 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q Q_INVOKABLE void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); - Q_INVOKABLE virtual void registerFunction(const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); + Q_INVOKABLE virtual void registerFunction(const QString& name, + ScriptEngine::FunctionSignature fun, + int numArguments = -1) override; /*@jsdoc * @function Script.registerFunction @@ -172,7 +177,10 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q int numArguments = -1); - Q_INVOKABLE virtual void registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1); + Q_INVOKABLE virtual void registerFunction(const QString& parent, + const QString& name, + ScriptEngine::FunctionSignature fun, + int numArguments = -1) override; /*@jsdoc * @function Script.registerEnum @@ -183,7 +191,7 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q // WARNING: This function must be called after a registerGlobalObject that creates the namespace this enum is located in, or // the globalObject won't function. E.g., if you have a Foo object and a Foo.FooType enum, Foo must be registered first. /// registers a global enum - Q_INVOKABLE virtual void registerEnum(const QString& enumName, QMetaEnum newEnum); + Q_INVOKABLE virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) override; /*@jsdoc * @function Script.registerValue @@ -203,10 +211,11 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q * @deprecated This function is deprecated and will be removed. */ /// evaluate some code in the context of the ScriptEngineQtScript and return the result - Q_INVOKABLE virtual ScriptValue evaluate(const QString& program, const QString& fileName); // this is also used by the script tool widget + Q_INVOKABLE virtual ScriptValue evaluate(const QString& program, + const QString& fileName) override; // this is also used by the script tool widget - Q_INVOKABLE virtual ScriptValue evaluate(const ScriptProgramPointer& program); + Q_INVOKABLE virtual ScriptValue evaluate(const ScriptProgramPointer& program) override; /*@jsdoc * @function Script.evaluateInClosure @@ -215,7 +224,7 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q * @returns {object} Object. * @deprecated This function is deprecated and will be removed. */ - Q_INVOKABLE virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program); + Q_INVOKABLE virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) override; /*@jsdoc * Checks whether the application was compiled as a debug build. @@ -260,7 +269,7 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q * @param {number} deltaSize - Delta size. * @deprecated This function is deprecated and will be removed. */ - virtual void updateMemoryCost(const qint64& deltaSize); + virtual void updateMemoryCost(const qint64& deltaSize) override; signals: @@ -381,10 +390,11 @@ class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public Q void entityScriptDetailsUpdated(); public: // not for public use, but I don't like how Qt strings this along with private friend functions - virtual ScriptValue create(int type, const void* ptr); - virtual bool convert(const ScriptValue& value, int type, void* ptr); + virtual ScriptValue create(int type, const void* ptr) override; + virtual bool convert(const ScriptValue& value, int type, void* ptr) override; virtual void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, - ScriptEngine::DemarshalFunction demarshalFunc, const ScriptValue& prototype); + ScriptEngine::DemarshalFunction demarshalFunc, + const ScriptValue& prototype) override; protected: // like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 76533a49cbd..7597f7f8fe7 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -13,7 +13,9 @@ #include #include -#include "PointerEvent.h" + +#include +#include using QmlContextCallback = std::function; diff --git a/libraries/ui/src/ui/QmlWrapper.h b/libraries/ui/src/ui/QmlWrapper.h index 84873472b96..8e110ffee3c 100644 --- a/libraries/ui/src/ui/QmlWrapper.h +++ b/libraries/ui/src/ui/QmlWrapper.h @@ -12,6 +12,7 @@ #include #include +#include #include class ScriptEngine; From 803ec1b3b507f46a28cc6f96f246c6e97f296061 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Fri, 3 Sep 2021 19:12:54 -0700 Subject: [PATCH 13/34] more debugging using github compiler runs --- libraries/entities/src/EntityScriptingInterface.cpp | 8 ++++---- libraries/entities/src/EntityScriptingInterface.h | 2 +- .../src/graphics-scripting/GraphicsScriptingUtil.cpp | 2 +- libraries/script-engine/CMakeLists.txt | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index e9098c822b5..8d0b5daee31 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -48,7 +48,7 @@ const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}"; const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}"; -static void staticScriptInitializer(ScriptManager* manager) { +void staticEntityScriptInitializer(ScriptManager* manager) { auto scriptEngine = manager->engine().data(); auto entityScriptingInterface = DependencyManager::get(); @@ -76,7 +76,7 @@ static void staticScriptInitializer(ScriptManager* manager) { manager->connect(manager, &ScriptManager::releaseEntityPacketSenderMessages, entityScriptingInterface.data(), &EntityScriptingInterface::releaseEntityPacketSenderMessages, Qt::DirectConnection); } -STATIC_SCRIPT_INITIALIZER(staticScriptInitializer); +STATIC_SCRIPT_INITIALIZER(staticEntityScriptInitializer); EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) : _entityTree(nullptr), @@ -2433,7 +2433,7 @@ void EntityScriptingInterface::getMeshes(const QUuid& entityID, const ScriptValu EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::getMeshes no entity with ID" << entityID; - ScriptValueList args { engine->undefinedValue(), false }; + ScriptValueList args{ engine->undefinedValue(), engine->newValue(false) }; callback.call(ScriptValue(), args); return; } @@ -2446,7 +2446,7 @@ void EntityScriptingInterface::getMeshes(const QUuid& entityID, const ScriptValu ScriptValueList args{ resultAsScriptValue, engine->newValue(true) }; callback.call(ScriptValue(), args); } else { - ScriptValueList args { engine->undefinedValue(), engine->newValue(false) }; + ScriptValueList args{ engine->undefinedValue(), engine->newValue(false) }; callback.call(ScriptValue(), args); } } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 5e5f83a5c64..36fe1962c84 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -2541,7 +2541,7 @@ public slots: private: void attachDefaultEventHandlers(ScriptManager* manager); // called on first call to Script.addEventHandler - friend void staticScriptInitializer(ScriptManager* manager); + friend void staticEntityScriptInitializer(ScriptManager* manager); private slots: void releaseEntityPacketSenderMessages(bool wait); diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp index e42d3ad86ae..9730fd0ec87 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp @@ -114,7 +114,7 @@ ScriptValue jsBindCallback(const ScriptValue& value) { template T this_qobject_cast(ScriptEngine* engine) { auto context = engine ? engine->currentContext() : nullptr; - return scriptvalue_cast(context ? context->thisObject() : ScriptValue::NullValue); + return scriptvalue_cast(context ? context->thisObject() : engine ? engine->nullValue() : ScriptValue()); } QString toDebugString(QObject* tmp) { QString s; diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 83ba2c63cca..ec30d52bfc7 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -7,7 +7,6 @@ if (NOT ANDROID) target_quazip() endif () -link_hifi_libraries(shaders) -include_hifi_library_headers(networking) +link_hifi_libraries(networking) include_hifi_library_headers(octree) include_hifi_library_headers(shared) From cae568c01ba234a8ae60350eb3aee6f5a7041619 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Fri, 3 Sep 2021 22:48:32 -0700 Subject: [PATCH 14/34] more code review using github compiler runs --- libraries/entities/src/EntityEditFilters.cpp | 20 ++++----- libraries/entities/src/EntityEditFilters.h | 4 +- libraries/midi/CMakeLists.txt | 1 + libraries/midi/src/Midi.cpp | 11 +++++ libraries/script-engine/src/ScriptContext.h | 6 +++ libraries/script-engine/src/ScriptEngine.h | 3 ++ libraries/script-engine/src/ScriptManager.cpp | 3 -- libraries/script-engine/src/ScriptProgram.h | 6 +++ libraries/script-engine/src/ScriptValue.cpp | 4 +- libraries/script-engine/src/ScriptValue.h | 41 +++++++++++++++++++ .../script-engine/src/ScriptValueIterator.h | 3 ++ libraries/script-engine/src/Scriptable.cpp | 8 ++-- .../src/qtscript/ScriptContextQtAgent.h | 10 ++--- .../src/qtscript/ScriptContextQtWrapper.h | 4 +- .../src/qtscript/ScriptEngineQtScript.h | 4 +- .../src/qtscript/ScriptProgramQtWrapper.h | 4 +- .../qtscript/ScriptValueIteratorQtWrapper.h | 2 +- .../src/qtscript/ScriptValueQtWrapper.h | 2 +- 18 files changed, 100 insertions(+), 36 deletions(-) diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index c9f72bedca8..6901b0b1641 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -79,7 +79,7 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper auto oldProperties = propertiesIn.getDesiredProperties(); auto specifiedProperties = propertiesIn.getChangedProperties(); propertiesIn.setDesiredProperties(specifiedProperties); - ScriptValue inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true); + ScriptValue inputValues = propertiesIn.copyToScriptValue(filterData.engine.get(), false, true, true); propertiesIn.setDesiredProperties(oldProperties); auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. @@ -91,7 +91,7 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper // get the current properties for then entity and include them for the filter call if (existingEntity && filterData.wantsOriginalProperties) { auto currentProperties = existingEntity->getProperties(filterData.includedOriginalProperties); - ScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); + ScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine.get(), false, true, true); args << currentValues; } @@ -101,17 +101,17 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper auto zoneEntity = _tree->findEntityByEntityItemID(id); if (zoneEntity) { auto zoneProperties = zoneEntity->getProperties(filterData.includedZoneProperties); - ScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); + ScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine.get(), false, true, true); if (filterData.wantsZoneBoundingBox) { bool success = true; AABox aaBox = zoneEntity->getAABox(success); if (success) { ScriptValue boundingBox = filterData.engine->newObject(); - ScriptValue bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner()); - ScriptValue topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft()); - ScriptValue center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter()); - ScriptValue boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions()); + ScriptValue bottomRightNear = vec3ToScriptValue(filterData.engine.get(), aaBox.getCorner()); + ScriptValue topFarLeft = vec3ToScriptValue(filterData.engine.get(), aaBox.calcTopFarLeft()); + ScriptValue center = vec3ToScriptValue(filterData.engine.get(), aaBox.calcCenter()); + ScriptValue boundingBoxDimensions = vec3ToScriptValue(filterData.engine.get(), aaBox.getDimensions()); boundingBox.setProperty("brn", bottomRightNear); boundingBox.setProperty("tfl", topFarLeft); boundingBox.setProperty("center", center); @@ -169,10 +169,6 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper void EntityEditFilters::removeFilter(EntityItemID entityID) { QWriteLocker writeLock(&_lock); - FilterData filterData = _filterDataMap.value(entityID); - if (filterData.valid()) { - delete filterData.engine; - } _filterDataMap.remove(entityID); } @@ -273,7 +269,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { if (!hadUncaughtExceptions(*engine, urlString)) { // put the engine in the engine map (so we don't leak them, etc...) FilterData filterData; - filterData.engine = engine.get(); + filterData.engine = engine; filterData.rejectAll = false; // define the uncaughtException function diff --git a/libraries/entities/src/EntityEditFilters.h b/libraries/entities/src/EntityEditFilters.h index bf0653a6a41..cc44ff47fbe 100644 --- a/libraries/entities/src/EntityEditFilters.h +++ b/libraries/entities/src/EntityEditFilters.h @@ -43,10 +43,10 @@ class EntityEditFilters : public QObject, public Dependency { bool wantsZoneBoundingBox { false }; std::function uncaughtExceptions; - ScriptEngine* engine; + ScriptEnginePointer engine; bool rejectAll; - FilterData(): engine(nullptr), rejectAll(false) {}; + FilterData(): rejectAll(false) {}; bool valid() { return (rejectAll || (engine != nullptr && filterFn.isFunction() && uncaughtExceptions)); } }; diff --git a/libraries/midi/CMakeLists.txt b/libraries/midi/CMakeLists.txt index dc54819c2b9..a698dfc9bbc 100644 --- a/libraries/midi/CMakeLists.txt +++ b/libraries/midi/CMakeLists.txt @@ -1,3 +1,4 @@ set(TARGET_NAME midi) setup_hifi_library(Network) link_hifi_libraries(shared networking) +include_hifi_library_headers(script-engine) diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index 02d47198e96..6300c60453c 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -15,6 +15,9 @@ #include +#include +#include + #if defined Q_OS_WIN32 #include "Windows.h" #endif @@ -131,6 +134,14 @@ void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD } } +STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { + auto scriptEngine = manager->engine().data(); + + scriptEngine->registerGlobalObject("Midi", DependencyManager::get().data()); +}); + + + void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { switch (wMsg) { case MOM_OPEN: diff --git a/libraries/script-engine/src/ScriptContext.h b/libraries/script-engine/src/ScriptContext.h index 733d0b88f1b..9a38a67c71d 100644 --- a/libraries/script-engine/src/ScriptContext.h +++ b/libraries/script-engine/src/ScriptContext.h @@ -43,6 +43,9 @@ class ScriptFunctionContext { virtual QString functionName() const = 0; virtual FunctionType functionType() const = 0; virtual int lineNumber() const = 0; + +protected: + ~ScriptFunctionContext() {} // prevent explicit deletion of base class }; /// [ScriptInterface] Provides an engine-independent interface for QScriptContext @@ -58,6 +61,9 @@ class ScriptContext { virtual ScriptValue thisObject() const = 0; virtual ScriptValue throwError(const QString& text) = 0; virtual ScriptValue throwValue(const ScriptValue& value) = 0; + +protected: + ~ScriptContext() {} // prevent explicit deletion of base class }; #endif // hifi_ScriptContext_h diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index dd8d539f216..ce17a34ce3b 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -136,6 +136,9 @@ class ScriptEngine { virtual ScriptValue create(int type, const void* ptr) = 0; virtual bool convert(const ScriptValue& value, int type, void* ptr) = 0; virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df, const ScriptValue& prototype) = 0; + +protected: + ~ScriptEngine() {} // prevent explicit deletion of base class }; Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptEngine::QObjectWrapOptions); diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 8f3ab7b4058..8ff8ee045ce 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -57,7 +57,6 @@ #include -#include "../../midi/src/Midi.h" // FIXME why won't a simpler include work? #include "MIDIEvent.h" #include "SettingHandle.h" @@ -675,8 +674,6 @@ void ScriptManager::init() { scriptRegisterMetaType(scriptEngine, externalResourceBucketToScriptValue, externalResourceBucketFromScriptValue); scriptEngine->registerEnum("Script.ExternalPaths", QMetaEnum::fromType()); - scriptEngine->registerGlobalObject("Midi", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("Quat", &_quatLibrary); scriptEngine->registerGlobalObject("Vec3", &_vec3Library); scriptEngine->registerGlobalObject("Mat4", &_mat4Library); diff --git a/libraries/script-engine/src/ScriptProgram.h b/libraries/script-engine/src/ScriptProgram.h index 8301532c431..abfe0d2748c 100644 --- a/libraries/script-engine/src/ScriptProgram.h +++ b/libraries/script-engine/src/ScriptProgram.h @@ -28,6 +28,9 @@ class ScriptProgram { virtual ScriptSyntaxCheckResultPointer checkSyntax() const = 0; virtual QString fileName() const = 0; virtual QString sourceCode() const = 0; + +protected: + ~ScriptProgram() {} // prevent explicit deletion of base class }; /// [ScriptInterface] Provides an engine-independent interface for QScriptSyntaxCheckResult @@ -45,6 +48,9 @@ class ScriptSyntaxCheckResult { virtual int errorLineNumber() const = 0; virtual QString errorMessage() const = 0; virtual State state() const = 0; + +protected: + ~ScriptSyntaxCheckResult() {} // prevent explicit deletion of base class }; #endif // hifi_ScriptProgram_h diff --git a/libraries/script-engine/src/ScriptValue.cpp b/libraries/script-engine/src/ScriptValue.cpp index 83f8e6b50ab..df9729e3ae9 100644 --- a/libraries/script-engine/src/ScriptValue.cpp +++ b/libraries/script-engine/src/ScriptValue.cpp @@ -14,7 +14,7 @@ #include "ScriptEngineLogging.h" -class ScriptValueProxyNull : public ScriptValueProxy { +class ScriptValueProxyNull final : public ScriptValueProxy { public: virtual void release() override; virtual ScriptValueProxy* copy() const override; @@ -43,7 +43,7 @@ class ScriptValueProxyNull : public ScriptValueProxy { const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; virtual ScriptValue property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; - virtual void setData(const ScriptValue& val); + virtual void setData(const ScriptValue& val) override; virtual void setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) override; diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h index afb578a676c..bafbf349f1a 100644 --- a/libraries/script-engine/src/ScriptValue.h +++ b/libraries/script-engine/src/ScriptValue.h @@ -163,6 +163,9 @@ class ScriptValueProxy { virtual quint32 toUInt32() const = 0; virtual QVariant toVariant() const = 0; virtual QObject* toQObject() const = 0; + +protected: + ~ScriptValueProxy() {} // prevent explicit deletion of base class }; // the second template parameter is used to defer evaluation of calls to the engine until ScriptEngine isn't forward-declared @@ -178,155 +181,193 @@ void ScriptValue::setProperty(quint32 arrayIndex, const TYP& value, const Proper } ScriptValue::ScriptValue(const ScriptValue& src) : _proxy(src.ptr()->copy()) { + Q_ASSERT(_proxy != nullptr); } ScriptValue::~ScriptValue() { + Q_ASSERT(_proxy != nullptr); _proxy->release(); } ScriptValue& ScriptValue::operator=(const ScriptValue& other) { + Q_ASSERT(_proxy != nullptr); _proxy->release(); _proxy = other.ptr()->copy(); return *this; } ScriptValue ScriptValue::call(const ScriptValue& thisObject, const ScriptValueList& args) const { + Q_ASSERT(_proxy != nullptr); return _proxy->call(thisObject, args); } ScriptValue ScriptValue::call(const ScriptValue& thisObject, const ScriptValue& arguments) const { + Q_ASSERT(_proxy != nullptr); return _proxy->call(thisObject, arguments); } ScriptValue ScriptValue::construct(const ScriptValueList& args) const { + Q_ASSERT(_proxy != nullptr); return _proxy->construct(args); } ScriptValue ScriptValue::construct(const ScriptValue& arguments) const { + Q_ASSERT(_proxy != nullptr); return _proxy->construct(arguments); } ScriptValue ScriptValue::data() const { + Q_ASSERT(_proxy != nullptr); return _proxy->data(); } ScriptEnginePointer ScriptValue::engine() const { + Q_ASSERT(_proxy != nullptr); return _proxy->engine(); } bool ScriptValue::equals(const ScriptValue& other) const { + Q_ASSERT(_proxy != nullptr); return _proxy->equals(other); } bool ScriptValue::isArray() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isArray(); } bool ScriptValue::isBool() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isBool(); } bool ScriptValue::isError() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isError(); } bool ScriptValue::isFunction() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isFunction(); } bool ScriptValue::isNumber() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isNumber(); } bool ScriptValue::isNull() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isNull(); } bool ScriptValue::isObject() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isObject(); } bool ScriptValue::isString() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isString(); } bool ScriptValue::isUndefined() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isUndefined(); } bool ScriptValue::isValid() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isValid(); } bool ScriptValue::isVariant() const { + Q_ASSERT(_proxy != nullptr); return _proxy->isVariant(); } ScriptValueIteratorPointer ScriptValue::newIterator() const { + Q_ASSERT(_proxy != nullptr); return _proxy->newIterator(); } ScriptValue ScriptValue::property(const QString& name, const ResolveFlags& mode) const { + Q_ASSERT(_proxy != nullptr); return _proxy->property(name, mode); } ScriptValue ScriptValue::property(quint32 arrayIndex, const ResolveFlags& mode) const { + Q_ASSERT(_proxy != nullptr); return _proxy->property(arrayIndex, mode); } void ScriptValue::setData(const ScriptValue& val) { + Q_ASSERT(_proxy != nullptr); return _proxy->setData(val); } void ScriptValue::setProperty(const QString& name, const ScriptValue& value, const PropertyFlags& flags) { + Q_ASSERT(_proxy != nullptr); return _proxy->setProperty(name, value, flags); } void ScriptValue::setProperty(quint32 arrayIndex, const ScriptValue& value, const PropertyFlags& flags) { + Q_ASSERT(_proxy != nullptr); return _proxy->setProperty(arrayIndex, value, flags); } void ScriptValue::setPrototype(const ScriptValue& prototype) { + Q_ASSERT(_proxy != nullptr); return _proxy->setPrototype(prototype); } bool ScriptValue::strictlyEquals(const ScriptValue& other) const { + Q_ASSERT(_proxy != nullptr); return _proxy->strictlyEquals(other); } bool ScriptValue::toBool() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toBool(); } qint32 ScriptValue::toInt32() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toInt32(); } double ScriptValue::toInteger() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toInteger(); } double ScriptValue::toNumber() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toNumber(); } QString ScriptValue::toString() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toString(); } quint16 ScriptValue::toUInt16() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toUInt16(); } quint32 ScriptValue::toUInt32() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toUInt32(); } QVariant ScriptValue::toVariant() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toVariant(); } QObject* ScriptValue::toQObject() const { + Q_ASSERT(_proxy != nullptr); return _proxy->toQObject(); } diff --git a/libraries/script-engine/src/ScriptValueIterator.h b/libraries/script-engine/src/ScriptValueIterator.h index 6b383b8ae54..13ae8be74e6 100644 --- a/libraries/script-engine/src/ScriptValueIterator.h +++ b/libraries/script-engine/src/ScriptValueIterator.h @@ -31,6 +31,9 @@ class ScriptValueIterator { virtual QString name() const = 0; virtual void next() = 0; virtual ScriptValue value() const = 0; + +protected: + ~ScriptValueIterator() {} // prevent explicit deletion of base class }; #endif // hifi_ScriptValueIterator_h diff --git a/libraries/script-engine/src/Scriptable.cpp b/libraries/script-engine/src/Scriptable.cpp index b205e6c2880..1ba432b061f 100644 --- a/libraries/script-engine/src/Scriptable.cpp +++ b/libraries/script-engine/src/Scriptable.cpp @@ -11,14 +11,12 @@ #include "Scriptable.h" -#include - -static QThreadStorage ScriptContextStore; +static thread_local ScriptContext* ScriptContextStore; ScriptContext* Scriptable::context() { - return ScriptContextStore.localData(); + return ScriptContextStore; } void Scriptable::setContext(ScriptContext* context) { - ScriptContextStore.setLocalData(context); + ScriptContextStore = context; } diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h index 05f4254bf00..183e4a0befb 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h @@ -24,17 +24,17 @@ class QScriptValue; class ScriptContextQtWrapper; using ScriptContextQtPointer = QSharedPointer; -class ScriptContextQtAgent : public QScriptEngineAgent { +class ScriptContextQtAgent final : public QScriptEngineAgent { public: // construction inline ScriptContextQtAgent(ScriptEngineQtScript* engine, QScriptEngineAgent* prevAgent) : QScriptEngineAgent(engine), _engine(engine), _prevAgent(prevAgent) {} virtual ~ScriptContextQtAgent() {} public: // QScriptEngineAgent implementation - virtual void contextPop(); - virtual void contextPush(); - virtual void functionEntry(qint64 scriptId); - virtual void functionExit(qint64 scriptId, const QScriptValue& returnValue); + virtual void contextPop() override; + virtual void contextPush() override; + virtual void functionEntry(qint64 scriptId) override; + virtual void functionExit(qint64 scriptId, const QScriptValue& returnValue) override; private: // storage bool _contextActive = false; diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h index f93a59e7bce..7200654c27d 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h @@ -25,9 +25,9 @@ class QScriptContext; class ScriptEngineQtScript; /// [QtScript] Implements ScriptContext for QtScript and translates calls for QScriptContextInfo -class ScriptContextQtWrapper : public ScriptContext { +class ScriptContextQtWrapper final : public ScriptContext { public: // construction - inline ScriptContextQtWrapper(ScriptEngineQtScript* engine, QScriptContext* context) : _engine(engine), _context(context) {} + inline ScriptContextQtWrapper(ScriptEngineQtScript* engine, QScriptContext* context) : _context(context) , _engine(engine) {} static ScriptContextQtWrapper* unwrap(ScriptContext* val); inline QScriptContext* toQtValue() const { return _context; } diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 31a8f0cade5..6764499a39c 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -41,7 +41,9 @@ using ScriptContextQtPointer = QSharedPointer; Q_DECLARE_METATYPE(ScriptEngineQtScriptPointer); /// [QtScript] Implements ScriptEngine for QtScript and translates calls for QScriptEngine -class ScriptEngineQtScript : public QScriptEngine, public ScriptEngine, public QEnableSharedFromThis { +class ScriptEngineQtScript final : public QScriptEngine, + public ScriptEngine, + public QEnableSharedFromThis { Q_OBJECT public: // ScriptEngine implementation diff --git a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h index cfd7982a8a4..6849b71339e 100644 --- a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.h @@ -22,7 +22,7 @@ #include "ScriptEngineQtScript.h" /// [QtScript] Implements ScriptProgram for QtScript and translates calls for QScriptProgram -class ScriptProgramQtWrapper : public ScriptProgram { +class ScriptProgramQtWrapper final : public ScriptProgram { public: // construction inline ScriptProgramQtWrapper(ScriptEngineQtScript* engine, const QScriptProgram& value) : _engine(engine), _value(value) {} @@ -41,7 +41,7 @@ class ScriptProgramQtWrapper : public ScriptProgram { QScriptProgram _value; }; -class ScriptSyntaxCheckResultQtWrapper : public ScriptSyntaxCheckResult { +class ScriptSyntaxCheckResultQtWrapper final : public ScriptSyntaxCheckResult { public: // construction inline ScriptSyntaxCheckResultQtWrapper(QScriptSyntaxCheckResult&& value) : _value(std::move(value)) {} diff --git a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h index 54d3bd6116c..00b618c6ded 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueIteratorQtWrapper.h @@ -23,7 +23,7 @@ #include "ScriptValueQtWrapper.h" /// [QtScript] Implements ScriptValueIterator for QtScript and translates calls for QScriptValueIterator -class ScriptValueIteratorQtWrapper : public ScriptValueIterator { +class ScriptValueIteratorQtWrapper final : public ScriptValueIterator { public: // construction inline ScriptValueIteratorQtWrapper(ScriptEngineQtScript* engine, const ScriptValue& object) : _engine(engine), _value(ScriptValueQtWrapper::fullUnwrap(engine, object)) {} diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h index 236c773633a..bce207ddbf1 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.h @@ -24,7 +24,7 @@ #include "ScriptEngineQtScript.h" /// [QtScript] Implements ScriptValue for QtScript and translates calls for QScriptValue -class ScriptValueQtWrapper : public ScriptValueProxy { +class ScriptValueQtWrapper final : public ScriptValueProxy { public: // construction inline ScriptValueQtWrapper(ScriptEngineQtScript* engine, const QScriptValue& value) : _engine(engine), _value(value) {} From 1d676285cf768255e07d56d37e14e24ebff031d0 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sat, 4 Sep 2021 00:14:59 -0700 Subject: [PATCH 15/34] more code review using github compiler runs (hopefully the macos build will link with this) --- libraries/entities-renderer/CMakeLists.txt | 3 +- .../src/qtscript/ScriptContextQtWrapper.h | 2 +- .../src/qtscript/ScriptEngineQtScript.cpp | 73 ------------------- 3 files changed, 2 insertions(+), 76 deletions(-) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index ac663abac3f..3dcf41c8456 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,11 +1,10 @@ set(TARGET_NAME entities-renderer) setup_hifi_library(Network) -link_hifi_libraries(shared workload gpu shaders procedural graphics material-networking model-networking script-engine render render-utils image qml ui pointers) +link_hifi_libraries(shared workload gpu shaders procedural graphics material-networking model-networking script-engine render render-utils image qml ui pointers entities) include_hifi_library_headers(animation) include_hifi_library_headers(audio) include_hifi_library_headers(avatars) include_hifi_library_headers(controllers) -include_hifi_library_headers(entities) include_hifi_library_headers(gl) include_hifi_library_headers(graphics-scripting) # for Forward.h include_hifi_library_headers(hfm) diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h index 7200654c27d..bbf9f0465cf 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.h @@ -48,7 +48,7 @@ class ScriptContextQtWrapper final : public ScriptContext { ScriptEngineQtScript* _engine; }; -class ScriptFunctionContextQtWrapper : public ScriptFunctionContext { +class ScriptFunctionContextQtWrapper final : public ScriptFunctionContext { public: // construction inline ScriptFunctionContextQtWrapper(QScriptContext* context) : _value(context) {} diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index f18bf1d0102..66a3fb455ad 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -52,15 +52,10 @@ #include "ScriptProgramQtWrapper.h" #include "ScriptValueQtWrapper.h" -static const int MAX_MODULE_ID_LENGTH { 4096 }; static const int MAX_DEBUG_VALUE_LENGTH { 80 }; static const QScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects; -static const QScriptValue::PropertyFlags READONLY_PROP_FLAGS { QScriptValue::ReadOnly | QScriptValue::Undeletable }; -static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_PROP_FLAGS | QScriptValue::SkipInEnumeration }; - -static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; Q_DECLARE_METATYPE(ScriptValue); @@ -315,74 +310,6 @@ void ScriptEngineQtScript::_debugDump(const QString& header, const QScriptValue& } #endif -static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { - // assemble the message by concatenating our arguments - QString message = ""; - for (int i = 0; i < context->argumentCount(); i++) { - if (i > 0) { - message += " "; - } - message += context->argument(i).toString(); - } - - // was this generated by a script engine? If we don't recognize it then send the message and exit - ScriptEngineQtScript* scriptEngine = qobject_cast(engine); - if (!scriptEngine) { - qCDebug(scriptengine_script, "%s", qUtf8Printable(message)); - return QScriptValue(); - } - - QString filename; - auto scriptManager = scriptEngine->manager(); - if (scriptManager) { - filename = scriptManager->getFilename(); - } - - // This message was sent by one of our script engines, let's try to see if we can find the source. - // Note that the first entry in the backtrace should be "print" and is somewhat useless to us - AbstractLoggerInterface* loggerInterface = AbstractLoggerInterface::get(); - if (loggerInterface && loggerInterface->showSourceDebugging()) { - QScriptContext* userContext = context; - while (userContext && QScriptContextInfo(userContext).functionType() == QScriptContextInfo::NativeFunction) { - userContext = userContext->parentContext(); - } - QString location; - if (userContext) { - QScriptContextInfo contextInfo(userContext); - QString fileName = contextInfo.fileName(); - int lineNumber = contextInfo.lineNumber(); - QString functionName = contextInfo.functionName(); - - location = functionName; - if (!fileName.isEmpty()) { - if (location.isEmpty()) { - location = fileName; - } else { - location = QString("%1 at %2").arg(location).arg(fileName); - } - } - if (lineNumber != -1) { - location = QString("%1:%2").arg(location).arg(lineNumber); - } - } - if (location.isEmpty()) { - location = filename; - } - - // give the script engine a chance to notify the system about this message - scriptEngine->print(message); - - // send the message to debug log - qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(location), qUtf8Printable(message)); - } else { - scriptEngine->print(message); - // prefix the script engine name to help disambiguate messages in the main debug log - qCDebug(scriptengine_script, "[%s] %s", qUtf8Printable(filename), qUtf8Printable(message)); - } - - return QScriptValue(); -} - static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValue& src) { return ScriptValueQtWrapper::fullUnwrap(static_cast(engine), src); } From 2b6084258fe228de4351fdfd68889136849407a2 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sat, 4 Sep 2021 01:22:43 -0700 Subject: [PATCH 16/34] hopefully resolves the last reported link error on macos --- libraries/avatars-renderer/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index a1a00582df0..dfc1126be5c 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME avatars-renderer) setup_hifi_library(Network) -link_hifi_libraries(shared shaders gpu graphics animation material-networking model-networking render render-utils image entities-renderer physics) +link_hifi_libraries(shared shaders gpu graphics animation material-networking model-networking render render-utils image entities-renderer physics recording) include_hifi_library_headers(audio) include_hifi_library_headers(avatars) include_hifi_library_headers(entities) @@ -11,7 +11,6 @@ include_hifi_library_headers(model-serializers) include_hifi_library_headers(networking) include_hifi_library_headers(octree) include_hifi_library_headers(procedural) -include_hifi_library_headers(recording) include_hifi_library_headers(script-engine) include_hifi_library_headers(task) include_hifi_library_headers(workload) From 876736aae4bf2c219b4b570f2fdb7e69e6f217c7 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sat, 4 Sep 2021 02:16:01 -0700 Subject: [PATCH 17/34] finished coding and smoketested ScriptContextQtAgent (required to get Scriptable functional for its users) --- .../script-engine/src/qtscript/ScriptContextQtAgent.h | 2 +- .../script-engine/src/qtscript/ScriptEngineQtScript.cpp | 8 +++++++- .../script-engine/src/qtscript/ScriptEngineQtScript.h | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h index 183e4a0befb..38e64ffc221 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h @@ -19,9 +19,9 @@ #include "ScriptEngineQtScript.h" class QScriptContext; -class QScriptEngine; class QScriptValue; class ScriptContextQtWrapper; +class ScriptEngineQtScript; using ScriptContextQtPointer = QSharedPointer; class ScriptContextQtAgent final : public QScriptEngineAgent { diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index 66a3fb455ad..bb686480f7c 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -51,6 +51,7 @@ #include "ScriptContextQtWrapper.h" #include "ScriptProgramQtWrapper.h" #include "ScriptValueQtWrapper.h" +#include "ScriptContextQtAgent.h" static const int MAX_DEBUG_VALUE_LENGTH { 80 }; @@ -348,6 +349,9 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : _undefinedValue = ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(undefined))); QScriptEngine::setProcessEventsInterval(MSECS_PER_SECOND); + + _contextAgent = new ScriptContextQtAgent(this, agent()); + setAgent(_contextAgent); } bool ScriptEngineQtScript::isDebugMode() const { @@ -358,7 +362,9 @@ bool ScriptEngineQtScript::isDebugMode() const { #endif } -ScriptEngineQtScript::~ScriptEngineQtScript() {} +ScriptEngineQtScript::~ScriptEngineQtScript() { + delete _contextAgent; +} void ScriptEngineQtScript::disconnectNonEssentialSignals() { disconnect(); diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 6764499a39c..c87f6f76795 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -33,6 +33,7 @@ #include "ArrayBufferClass.h" class ScriptContextQtWrapper; +class ScriptContextQtAgent; class ScriptEngineQtScript; class ScriptManager; using ScriptEngineQtScriptPointer = QSharedPointer; @@ -432,6 +433,8 @@ class ScriptEngineQtScript final : public QScriptEngine, qint64 _lastUpdate; ArrayBufferClass* _arrayBufferClass; + + ScriptContextQtAgent* _contextAgent{ nullptr }; }; // Lambda helps create callable QScriptValues out of std::functions: From 4abbff217796c5e2fbb48d029dc0270f8fd9b0a1 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sat, 4 Sep 2021 03:23:44 -0700 Subject: [PATCH 18/34] patch review and removal of unnecessary differences --- interface/src/avatar/MyAvatar.cpp | 1 - .../AssetMappingsScriptingInterface.cpp | 1 - libraries/animation/CMakeLists.txt | 2 +- libraries/avatars-renderer/CMakeLists.txt | 14 +++++++------- libraries/avatars/src/AvatarData.h | 2 +- .../impl/conditionals/ScriptConditional.cpp | 2 -- libraries/entities-renderer/CMakeLists.txt | 16 ++++++++-------- libraries/midi/src/Midi.cpp | 2 -- .../src/qtscript/ArrayBufferViewClass.cpp | 5 +++-- 9 files changed, 20 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7643dc48ce2..d23e82cdf5f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -379,7 +379,6 @@ MyAvatar::MyAvatar(QThread* thread) : MyAvatar::~MyAvatar() { _lookAtTargetAvatar.reset(); - _scriptEngine.reset(); if (_addAvatarEntitiesToTreeTimer.isActive()) { _addAvatarEntitiesToTreeTimer.stop(); } diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index d7a3eac9f88..0c80d0384df 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -11,7 +11,6 @@ #include "AssetMappingsScriptingInterface.h" -#include #include #include diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index a18f6c24827..d005480a313 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -1,10 +1,10 @@ set(TARGET_NAME animation) setup_hifi_library(Network) link_hifi_libraries(shared graphics model-serializers script-engine) +include_hifi_library_headers(networking) include_hifi_library_headers(gpu) include_hifi_library_headers(hfm) include_hifi_library_headers(image) -include_hifi_library_headers(networking) target_nsight() diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index dfc1126be5c..964af7085e9 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -1,18 +1,18 @@ set(TARGET_NAME avatars-renderer) setup_hifi_library(Network) link_hifi_libraries(shared shaders gpu graphics animation material-networking model-networking render render-utils image entities-renderer physics recording) -include_hifi_library_headers(audio) include_hifi_library_headers(avatars) -include_hifi_library_headers(entities) -include_hifi_library_headers(graphics-scripting) # for ScriptableModel.h +include_hifi_library_headers(networking) include_hifi_library_headers(hfm) -include_hifi_library_headers(ktx) include_hifi_library_headers(model-serializers) -include_hifi_library_headers(networking) -include_hifi_library_headers(octree) +include_hifi_library_headers(ktx) include_hifi_library_headers(procedural) -include_hifi_library_headers(script-engine) +include_hifi_library_headers(audio) +include_hifi_library_headers(entities) +include_hifi_library_headers(octree) include_hifi_library_headers(task) include_hifi_library_headers(workload) +include_hifi_library_headers(graphics-scripting) # for ScriptableModel.h +include_hifi_library_headers(script-engine) target_bullet() diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index bb1c1ddca59..520e325ee0e 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -48,7 +48,7 @@ #include #include #include -#include "Scriptable.h" +#include #include #include "AABox.h" diff --git a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp index bd459ca3ffa..277b63ed112 100644 --- a/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp +++ b/libraries/controllers/src/controllers/impl/conditionals/ScriptConditional.cpp @@ -10,8 +10,6 @@ #include -#include - using namespace controller; bool ScriptConditional::satisfied() { diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 3dcf41c8456..54e108247a1 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,19 +1,19 @@ set(TARGET_NAME entities-renderer) setup_hifi_library(Network) link_hifi_libraries(shared workload gpu shaders procedural graphics material-networking model-networking script-engine render render-utils image qml ui pointers entities) -include_hifi_library_headers(animation) -include_hifi_library_headers(audio) -include_hifi_library_headers(avatars) -include_hifi_library_headers(controllers) +include_hifi_library_headers(networking) include_hifi_library_headers(gl) -include_hifi_library_headers(graphics-scripting) # for Forward.h -include_hifi_library_headers(hfm) include_hifi_library_headers(ktx) -include_hifi_library_headers(model-serializers) -include_hifi_library_headers(networking) include_hifi_library_headers(octree) +include_hifi_library_headers(audio) include_hifi_library_headers(physics) +include_hifi_library_headers(animation) +include_hifi_library_headers(hfm) +include_hifi_library_headers(model-serializers) +include_hifi_library_headers(avatars) +include_hifi_library_headers(controllers) include_hifi_library_headers(task) +include_hifi_library_headers(graphics-scripting) # for Forward.h target_bullet() target_polyvox() diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index 6300c60453c..c9b7b348a86 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -140,8 +140,6 @@ STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { scriptEngine->registerGlobalObject("Midi", DependencyManager::get().data()); }); - - void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { switch (wMsg) { case MOM_OPEN: diff --git a/libraries/script-engine/src/qtscript/ArrayBufferViewClass.cpp b/libraries/script-engine/src/qtscript/ArrayBufferViewClass.cpp index fa1c114b5be..f58cbeb9433 100644 --- a/libraries/script-engine/src/qtscript/ArrayBufferViewClass.cpp +++ b/libraries/script-engine/src/qtscript/ArrayBufferViewClass.cpp @@ -16,8 +16,9 @@ Q_DECLARE_METATYPE(QByteArray*) ArrayBufferViewClass::ArrayBufferViewClass(ScriptEngineQtScript* scriptEngine) : QObject(scriptEngine), -QScriptClass(scriptEngine), -_scriptEngine(scriptEngine) { + QScriptClass(scriptEngine), + _scriptEngine(scriptEngine) +{ // Save string handles for quick lookup _bufferName = engine()->toStringHandle(BUFFER_PROPERTY_NAME.toLatin1()); _byteOffsetName = engine()->toStringHandle(BYTE_OFFSET_PROPERTY_NAME.toLatin1()); From 28d79646b2fd8651f10536b7649a76c2af654738 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 5 Sep 2021 23:36:22 -0700 Subject: [PATCH 19/34] significant cleanup of ScriptEngineQtScript (which isn't exposed to the scripting engine and shouldn't be @jsdoc'ed) --- libraries/script-engine/src/ScriptEngine.h | 1 + libraries/script-engine/src/ScriptManager.cpp | 4 + libraries/script-engine/src/ScriptManager.h | 17 +- .../src/qtscript/ScriptEngineQtScript.cpp | 37 --- .../src/qtscript/ScriptEngineQtScript.h | 246 +----------------- 5 files changed, 17 insertions(+), 288 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index ce17a34ce3b..d7729ce75fb 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -116,6 +116,7 @@ class ScriptEngine { virtual QStringList uncaughtExceptionBacktrace() const = 0; virtual int uncaughtExceptionLineNumber() const = 0; virtual void updateMemoryCost(const qint64& deltaSize) = 0; + virtual void requestCollectGarbage() = 0; public: // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 8ff8ee045ce..44394d9733c 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -2470,3 +2470,7 @@ QString ScriptManager::formatException(const ScriptValue& exception, bool includ ScriptValue ScriptManager::evaluate(const QString& program, const QString& fileName) { return _engine->evaluate(program, fileName); } + +void ScriptManager::requestGarbageCollection() { + _engine->requestCollectGarbage(); +} diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index bf6cb36339c..7723c9b7be1 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -411,7 +411,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi QVariantMap fetchModuleSource(const QString& modulePath, const bool forceDownload = false); ScriptValue instantiateModule(const ScriptValue& module, const QString& sourceCode); - Q_INVOKABLE ScriptValue evaluate(const QString& program, const QString& fileName = QString()); + ScriptValue evaluate(const QString& program, const QString& fileName = QString()); /*@jsdoc * Calls a function repeatedly, at a set interval. @@ -534,6 +534,13 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi QVariant cloneEntityScriptDetails(const EntityItemID& entityID); QFuture getLocalEntityScriptDetails(const EntityItemID& entityID) override; + /*@jsdoc + * Manually runs the JavaScript garbage collector which reclaims memory by disposing of objects that are no longer + * reachable. + * @function Script.requestGarbageCollection + */ + Q_INVOKABLE void requestGarbageCollection(); + /*@jsdoc * @function Script.loadEntityScript * @param {Uuid} entityID - Entity ID. @@ -722,14 +729,6 @@ public slots: */ void finished(const QString& fileNameString, ScriptManagerPointer); - /*@jsdoc - * @function Script.cleanupMenuItem - * @param {string} menuItem - Menu item. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void cleanupMenuItem(const QString& menuItemString); - /*@jsdoc * Triggered when the script prints a message to the program log via {@link print}, {@link Script.print}, * {@link console.log}, {@link console.debug}, {@link console.group}, {@link console.groupEnd}, {@link console.time}, or diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index bb686480f7c..c4a00188f12 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -354,37 +354,10 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : setAgent(_contextAgent); } -bool ScriptEngineQtScript::isDebugMode() const { -#if defined(DEBUG) - return true; -#else - return false; -#endif -} - ScriptEngineQtScript::~ScriptEngineQtScript() { delete _contextAgent; } -void ScriptEngineQtScript::disconnectNonEssentialSignals() { - disconnect(); - QThread* workerThread; - // Ensure the thread should be running, and does exist - if (_isRunning && _isThreaded && (workerThread = QScriptEngine::thread())) { - connect(this, &QObject::destroyed, workerThread, &QThread::quit); - connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); - } -} - -void ScriptEngineQtScript::executeOnScriptThread(std::function function, const Qt::ConnectionType& type ) { - if (QThread::currentThread() != QScriptEngine::thread()) { - QMetaObject::invokeMethod(this, "executeOnScriptThread", type, Q_ARG(std::function, function)); - return; - } - - function(); -} - void ScriptEngineQtScript::registerEnum(const QString& enumName, QMetaEnum newEnum) { if (!newEnum.isValid()) { qCCritical(scriptengine) << "registerEnum called on invalid enum with name " << enumName; @@ -768,16 +741,6 @@ void ScriptEngineQtScript::updateMemoryCost(const qint64& deltaSize) { } } -void ScriptEngineQtScript::print(const QString& message) { - QString filename; - auto scriptManager = manager(); - if (scriptManager) { - filename = scriptManager->getFilename(); - } - - emit printedMessage(message, filename); -} - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ScriptEngine implementation diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index c87f6f76795..fccdf8ef6dd 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -25,7 +25,6 @@ #include #include -#include #include "../ScriptEngine.h" #include "../ScriptManager.h" @@ -97,19 +96,14 @@ class ScriptEngineQtScript final : public QScriptEngine, virtual ScriptValue uncaughtException() const override; virtual QStringList uncaughtExceptionBacktrace() const override; virtual int uncaughtExceptionLineNumber() const override; + virtual void updateMemoryCost(const qint64& deltaSize) override; + virtual void requestCollectGarbage() override { collectGarbage(); } // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways inline bool IS_THREADSAFE_INVOCATION(const QString& method) { return ScriptEngine::IS_THREADSAFE_INVOCATION(method); } protected: // brought over from BaseScriptEngine - /*@jsdoc - * @function Script.makeError - * @param {object} [other] - Other. - * @param {string} [type="Error"] - Error. - * @returns {object} Object. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE QScriptValue makeError(const QScriptValue& other = QScriptValue(), const QString& type = "Error"); + QScriptValue makeError(const QScriptValue& other = QScriptValue(), const QString& type = "Error"); // if the currentContext() is valid then throw the passed exception; otherwise, immediately emit it. // note: this is used in cases where C++ code might call into JS API methods directly @@ -126,23 +120,9 @@ class ScriptEngineQtScript final : public QScriptEngine, // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can // properly ensure they are only called on the correct thread - /*@jsdoc - * @function Script.registerGlobalObject - * @param {string} name - Name. - * @param {object} object - Object. - * @deprecated This function is deprecated and will be removed. - */ /// registers a global object by name Q_INVOKABLE virtual void registerGlobalObject(const QString& name, QObject* object) override; - /*@jsdoc - * @function Script.registerGetterSetter - * @param {string} name - Name. - * @param {function} getter - Getter. - * @param {function} setter - Setter. - * @param {string} [parent=""] - Parent. - * @deprecated This function is deprecated and will be removed. - */ /// registers a global getter/setter Q_INVOKABLE void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, const QString& parent = QString("")); @@ -152,13 +132,6 @@ class ScriptEngineQtScript final : public QScriptEngine, ScriptEngine::FunctionSignature setter, const QString& parent = QString("")) override; - /*@jsdoc - * @function Script.registerFunction - * @param {string} name - Name. - * @param {function} function - Function. - * @param {number} [numArguments=-1] - Number of arguments. - * @deprecated This function is deprecated and will be removed. - */ /// register a global function Q_INVOKABLE void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); @@ -167,14 +140,6 @@ class ScriptEngineQtScript final : public QScriptEngine, ScriptEngine::FunctionSignature fun, int numArguments = -1) override; - /*@jsdoc - * @function Script.registerFunction - * @param {string} parent - Parent. - * @param {string} name - Name. - * @param {function} function - Function. - * @param {number} [numArguments=-1] - Number of arguments. - * @deprecated This function is deprecated and will be removed. - */ /// register a function as a method on a previously registered global object Q_INVOKABLE void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); @@ -185,34 +150,14 @@ class ScriptEngineQtScript final : public QScriptEngine, ScriptEngine::FunctionSignature fun, int numArguments = -1) override; - /*@jsdoc - * @function Script.registerEnum - * @param {string} name - Name. - * @param {object} enum - Enum. - * @deprecated This function is deprecated and will be removed. - */ // WARNING: This function must be called after a registerGlobalObject that creates the namespace this enum is located in, or // the globalObject won't function. E.g., if you have a Foo object and a Foo.FooType enum, Foo must be registered first. /// registers a global enum Q_INVOKABLE virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) override; - /*@jsdoc - * @function Script.registerValue - * @param {string} name - Name. - * @param {object} value - Value. - * @deprecated This function is deprecated and will be removed. - */ /// registers a global object by name Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value); - /*@jsdoc - * @function Script.evaluate - * @param {string} program - Program. - * @param {string} filename - File name. - * @param {number} [lineNumber=-1] - Line number. - * @returns {object} Object. - * @deprecated This function is deprecated and will be removed. - */ /// evaluate some code in the context of the ScriptEngineQtScript and return the result Q_INVOKABLE virtual ScriptValue evaluate(const QString& program, const QString& fileName) override; // this is also used by the script tool widget @@ -220,177 +165,10 @@ class ScriptEngineQtScript final : public QScriptEngine, Q_INVOKABLE virtual ScriptValue evaluate(const ScriptProgramPointer& program) override; - /*@jsdoc - * @function Script.evaluateInClosure - * @param {object} locals - Locals. - * @param {object} program - Program. - * @returns {object} Object. - * @deprecated This function is deprecated and will be removed. - */ Q_INVOKABLE virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) override; - /*@jsdoc - * Checks whether the application was compiled as a debug build. - * @function Script.isDebugMode - * @returns {boolean} true if the application was compiled as a debug build, false if it was - * compiled as a release build. - */ - Q_INVOKABLE bool isDebugMode() const; - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // MODULE related methods - - /*@jsdoc - * Prints a message to the program log and emits {@link Script.printedMessage}. - *

Alternatively, you can use {@link print} or one of the {@link console} API methods.

- * @function Script.print - * @param {string} message - The message to print. - */ - Q_INVOKABLE void print(const QString& message); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Entity Script Related methods - - /*@jsdoc - * Manually runs the JavaScript garbage collector which reclaims memory by disposing of objects that are no longer - * reachable. - * @function Script.requestGarbageCollection - */ - Q_INVOKABLE void requestGarbageCollection() { collectGarbage(); } - - bool isRunning() const { return _isRunning; } // used by ScriptWidget - - bool isDebuggable() const { return _debuggable; } - - void disconnectNonEssentialSignals(); - // NOTE - this is used by the TypedArray implementation. we need to review this for thread safety - ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - - /*@jsdoc - * @function Script.updateMemoryCost - * @param {number} deltaSize - Delta size. - * @deprecated This function is deprecated and will be removed. - */ - virtual void updateMemoryCost(const qint64& deltaSize) override; - -signals: - - /*@jsdoc - * Triggered frequently at a system-determined interval. - * @function Script.update - * @param {number} deltaTime - The time since the last update, in s. - * @returns {Signal} - * @example Report script update intervals. - * Script.update.connect(function (deltaTime) { - * print("Update: " + deltaTime); - * }); - */ - void update(float deltaTime); - - /*@jsdoc - * @function Script.finished - * @param {string} filename - File name. - * @param {object} engine - Engine. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void finished(const QString& fileNameString, ScriptEngineQtScriptPointer); - - /*@jsdoc - * @function Script.cleanupMenuItem - * @param {string} menuItem - Menu item. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void cleanupMenuItem(const QString& menuItemString); - - /*@jsdoc - * Triggered when the script prints a message to the program log via {@link print}, {@link Script.print}, - * {@link console.log}, {@link console.debug}, {@link console.group}, {@link console.groupEnd}, {@link console.time}, or - * {@link console.timeEnd}. - * @function Script.printedMessage - * @param {string} message - The message. - * @param {string} scriptName - The name of the script that generated the message. - * @returns {Signal} - */ - void printedMessage(const QString& message, const QString& scriptName); - - /*@jsdoc - * Triggered when the script generates an error, {@link console.error} or {@link console.exception} is called, or - * {@link console.assert} is called and fails. - * @function Script.errorMessage - * @param {string} message - The error message. - * @param {string} scriptName - The name of the script that generated the error message. - * @returns {Signal} - */ - void errorMessage(const QString& message, const QString& scriptName); - - /*@jsdoc - * Triggered when the script generates a warning or {@link console.warn} is called. - * @function Script.warningMessage - * @param {string} message - The warning message. - * @param {string} scriptName - The name of the script that generated the warning message. - * @returns {Signal} - */ - void warningMessage(const QString& message, const QString& scriptName); - - /*@jsdoc - * Triggered when the script generates an information message or {@link console.info} is called. - * @function Script.infoMessage - * @param {string} message - The information message. - * @param {string} scriptName - The name of the script that generated the information message. - * @returns {Signal} - */ - void infoMessage(const QString& message, const QString& scriptName); - - /*@jsdoc - * Triggered when the running state of the script changes, e.g., from running to stopping. - * @function Script.runningStateChanged - * @returns {Signal} - */ - void runningStateChanged(); - - /*@jsdoc - * @function Script.clearDebugWindow - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void clearDebugWindow(); - - /*@jsdoc - * @function Script.loadScript - * @param {string} scriptName - Script name. - * @param {boolean} isUserLoaded - Is user loaded. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void loadScript(const QString& scriptName, bool isUserLoaded); - - /*@jsdoc - * @function Script.reloadScript - * @param {string} scriptName - Script name. - * @param {boolean} isUserLoaded - Is user loaded. - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - void reloadScript(const QString& scriptName, bool isUserLoaded); - - /*@jsdoc - * Triggered when the script has stopped. - * @function Script.doneRunning - * @returns {Signal} - */ - void doneRunning(); - - /*@jsdoc - * @function Script.entityScriptDetailsUpdated - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. - */ - // Emitted when an entity script is added or removed, or when the status of an entity - // script is updated (goes from RUNNING to ERROR_RUNNING_SCRIPT, for example) - void entityScriptDetailsUpdated(); + inline ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } public: // not for public use, but I don't like how Qt strings this along with private friend functions virtual ScriptValue create(int type, const void* ptr) override; @@ -409,15 +187,6 @@ class ScriptEngineQtScript final : public QScriptEngine, const QScriptEngine::ValueOwnership& ownership = QScriptEngine::AutoOwnership); protected: - - /*@jsdoc - * @function Script.executeOnScriptThread - * @param {function} function - Function. - * @param {ConnectionType} [type=2] - Connection type. - * @deprecated This function is deprecated and will be removed. - */ - Q_INVOKABLE void executeOnScriptThread(std::function function, const Qt::ConnectionType& type = Qt::QueuedConnection ); - QPointer _manager; int _nextCustomType = 0; @@ -425,13 +194,6 @@ class ScriptEngineQtScript final : public QScriptEngine, ScriptValue _undefinedValue; mutable ScriptContextQtPointer _currContext; - std::atomic _isRunning { false }; - - bool _isThreaded { false }; - QScriptEngineDebugger* _debugger { nullptr }; - bool _debuggable { false }; - qint64 _lastUpdate; - ArrayBufferClass* _arrayBufferClass; ScriptContextQtAgent* _contextAgent{ nullptr }; From ff46561a102a199f31ae94ce88dfc8fbfd784f4f Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Mon, 6 Sep 2021 00:10:02 -0700 Subject: [PATCH 20/34] more simplification of ScriptEngineQtScript declarations --- .../src/qtscript/ScriptEngineQtScript.h | 57 ++++++------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index fccdf8ef6dd..da915d1f461 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -51,9 +51,9 @@ class ScriptEngineQtScript final : public QScriptEngine, virtual void clearExceptions() override; virtual ScriptValue cloneUncaughtException(const QString& detail = QString()) override; virtual ScriptContext* currentContext() const override; - //virtual ScriptValue evaluate(const QString& program, const QString& fileName = QString()) override; - //virtual ScriptValue evaluate(const ScriptProgramPointer &program) override; - //virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) override; + Q_INVOKABLE virtual ScriptValue evaluate(const QString& program, const QString& fileName = QString()) override; + Q_INVOKABLE virtual ScriptValue evaluate(const ScriptProgramPointer& program) override; + Q_INVOKABLE virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) override; virtual ScriptValue globalObject() const override; virtual bool hasUncaughtException() const override; virtual bool isEvaluating() const override; @@ -81,11 +81,19 @@ class ScriptEngineQtScript final : public QScriptEngine, virtual ScriptValue newVariant(const QVariant& value) override; virtual ScriptValue nullValue() override; virtual bool raiseException(const ScriptValue& exception) override; - //virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) override; - //Q_INVOKABLE virtual void registerFunction(const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1) override; - //Q_INVOKABLE virtual void registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature fun, int numArguments = -1) override; - //Q_INVOKABLE virtual void registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent = QString("")) override; - //virtual void registerGlobalObject(const QString& name, QObject* object) override; + Q_INVOKABLE virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) override; + Q_INVOKABLE virtual void registerFunction(const QString& name, + ScriptEngine::FunctionSignature fun, + int numArguments = -1) override; + Q_INVOKABLE virtual void registerFunction(const QString& parent, + const QString& name, + ScriptEngine::FunctionSignature fun, + int numArguments = -1) override; + Q_INVOKABLE virtual void registerGetterSetter(const QString& name, + ScriptEngine::FunctionSignature getter, + ScriptEngine::FunctionSignature setter, + const QString& parent = QString("")) override; + Q_INVOKABLE virtual void registerGlobalObject(const QString& name, QObject* object) override; virtual void setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) override; virtual void setObjectName(const QString& name) override; virtual bool setProperty(const char* name, const QVariant& value) override; @@ -120,53 +128,20 @@ class ScriptEngineQtScript final : public QScriptEngine, // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can // properly ensure they are only called on the correct thread - /// registers a global object by name - Q_INVOKABLE virtual void registerGlobalObject(const QString& name, QObject* object) override; - /// registers a global getter/setter Q_INVOKABLE void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, const QString& parent = QString("")); - Q_INVOKABLE virtual void registerGetterSetter(const QString& name, - ScriptEngine::FunctionSignature getter, - ScriptEngine::FunctionSignature setter, - const QString& parent = QString("")) override; - /// register a global function Q_INVOKABLE void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); - - Q_INVOKABLE virtual void registerFunction(const QString& name, - ScriptEngine::FunctionSignature fun, - int numArguments = -1) override; - /// register a function as a method on a previously registered global object Q_INVOKABLE void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); - - Q_INVOKABLE virtual void registerFunction(const QString& parent, - const QString& name, - ScriptEngine::FunctionSignature fun, - int numArguments = -1) override; - - // WARNING: This function must be called after a registerGlobalObject that creates the namespace this enum is located in, or - // the globalObject won't function. E.g., if you have a Foo object and a Foo.FooType enum, Foo must be registered first. - /// registers a global enum - Q_INVOKABLE virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) override; - /// registers a global object by name Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value); - /// evaluate some code in the context of the ScriptEngineQtScript and return the result - Q_INVOKABLE virtual ScriptValue evaluate(const QString& program, - const QString& fileName) override; // this is also used by the script tool widget - - - Q_INVOKABLE virtual ScriptValue evaluate(const ScriptProgramPointer& program) override; - - Q_INVOKABLE virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) override; - // NOTE - this is used by the TypedArray implementation. we need to review this for thread safety inline ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } From 26c9810d8d049621ced7c1d2544e9464498ac300 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Mon, 6 Sep 2021 13:19:03 -0700 Subject: [PATCH 21/34] more shifting around of ScriptEngineQtScript declaration --- .../src/qtscript/ScriptEngineQtScript.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index da915d1f461..d073ad97497 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -46,6 +46,14 @@ class ScriptEngineQtScript final : public QScriptEngine, public QEnableSharedFromThis { Q_OBJECT +public: // construction + ScriptEngineQtScript(ScriptManager* scriptManager = nullptr); + ~ScriptEngineQtScript(); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can + // properly ensure they are only called on the correct thread + public: // ScriptEngine implementation virtual void abortEvaluation() override; virtual void clearExceptions() override; @@ -120,14 +128,7 @@ class ScriptEngineQtScript final : public QScriptEngine, // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways static bool IS_THREADSAFE_INVOCATION(const QThread* thread, const QString& method); -public: - ScriptEngineQtScript(ScriptManager* scriptManager = nullptr); - ~ScriptEngineQtScript(); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can - // properly ensure they are only called on the correct thread - +public: // public non-interface methods for other QtScript-specific classes to use /// registers a global getter/setter Q_INVOKABLE void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, const QString& parent = QString("")); From 4f03899febdbde0f6272a87588d06ccd1a6eb3e8 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sat, 11 Sep 2021 22:29:47 -0700 Subject: [PATCH 22/34] convert script engine variables from QSharedPointer to std::shared_ptr --- assignment-client/src/Agent.cpp | 6 ++-- assignment-client/src/Agent.h | 4 +-- .../src/scripts/EntityScriptServer.cpp | 18 +++++----- interface/src/Application.cpp | 36 +++++++++---------- interface/src/Application.h | 3 +- interface/src/avatar/MyAvatar.cpp | 6 ++-- interface/src/avatar/MyAvatar.h | 4 +-- interface/src/commerce/QmlCommerce.cpp | 2 +- interface/src/ui/JSConsole.cpp | 18 +++++----- interface/src/ui/JSConsole.h | 5 +-- interface/src/ui/TestingDialog.cpp | 2 +- interface/src/ui/TestingDialog.h | 5 +-- interface/src/ui/overlays/Overlays.cpp | 2 +- libraries/animation/src/AnimationObject.cpp | 2 +- libraries/audio/src/AudioEffectOptions.cpp | 2 +- .../audio/src/AudioScriptingInterface.cpp | 2 +- libraries/audio/src/ScriptAudioInjector.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/ScriptAvatarData.cpp | 2 +- libraries/baking/src/MaterialBaker.cpp | 6 ++-- .../src/controllers/ScriptingInterface.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 36 ++++++++++++------- .../src/EntityTreeRenderer.h | 6 ++-- .../src/ModelScriptingInterface.cpp | 2 +- .../src/ModelScriptingInterface.h | 7 ++-- libraries/entities/src/EntityEditFilters.cpp | 2 +- .../entities/src/EntityScriptingInterface.cpp | 17 ++++----- .../entities/src/EntityScriptingInterface.h | 12 ++++--- libraries/entities/src/EntityTree.cpp | 4 +-- libraries/midi/src/Midi.cpp | 2 +- .../src/AbstractScriptingServicesInterface.h | 4 +-- libraries/script-engine/src/ScriptContext.h | 9 ++--- libraries/script-engine/src/ScriptEngine.cpp | 2 +- libraries/script-engine/src/ScriptEngine.h | 7 ++-- libraries/script-engine/src/ScriptEngines.cpp | 22 ++++++------ libraries/script-engine/src/ScriptEngines.h | 1 - libraries/script-engine/src/ScriptManager.cpp | 30 ++++++++-------- libraries/script-engine/src/ScriptManager.h | 8 ++--- libraries/script-engine/src/ScriptProgram.h | 6 ++-- libraries/script-engine/src/ScriptValue.h | 7 ++-- .../script-engine/src/ScriptValueIterator.h | 5 +-- libraries/script-engine/src/Scriptable.h | 4 +-- .../src/qtscript/ScriptContextQtAgent.cpp | 4 +-- .../src/qtscript/ScriptContextQtAgent.h | 5 +-- .../src/qtscript/ScriptContextQtWrapper.cpp | 6 ++-- .../src/qtscript/ScriptEngineQtScript.cpp | 4 +-- .../src/qtscript/ScriptEngineQtScript.h | 10 +++--- .../src/qtscript/ScriptProgramQtWrapper.cpp | 2 +- .../src/qtscript/ScriptValueQtWrapper.cpp | 4 +-- 49 files changed, 194 insertions(+), 165 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 20453274779..c341437d710 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -606,7 +606,7 @@ void Agent::setIsAvatar(bool isAvatar) { // start the timer _avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS); - connect(_scriptManager.data(), &ScriptManager::update, + connect(_scriptManager.get(), &ScriptManager::update, scriptableAvatar.data(), &ScriptableAvatar::update, Qt::QueuedConnection); // tell the avatarAudioTimer to start ticking @@ -642,7 +642,7 @@ void Agent::setIsAvatar(bool isAvatar) { nodeList->sendPacket(std::move(packet), *node); }); - disconnect(_scriptManager.data(), &ScriptManager::update, + disconnect(_scriptManager.get(), &ScriptManager::update, scriptableAvatar.data(), &ScriptableAvatar::update); QMetaObject::invokeMethod(&_avatarAudioTimer, "stop"); @@ -879,7 +879,7 @@ void Agent::aboutToFinish() { // drop our shared pointer to the script engine, then ask ScriptEngines to shutdown scripting // this ensures that the ScriptEngine goes down before ScriptEngines - _scriptManager.clear(); + _scriptManager.reset(); { DependencyManager::get()->shutdownScripting(); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index d3ed93e3560..f526f313593 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -36,8 +36,8 @@ class ScriptEngine; class ScriptManager; -using ScriptEnginePointer = QSharedPointer; -using ScriptManagerPointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; +using ScriptManagerPointer = std::shared_ptr; class Agent : public ThreadedAssignment { Q_OBJECT diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 17536ffc974..b08380959e2 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -459,12 +459,12 @@ void EntityScriptServer::resetEntitiesScriptEngine() { // connect this script engines printedMessage signal to the global ScriptEngines these various messages auto scriptEngines = DependencyManager::get().data(); - connect(newManager.data(), &ScriptManager::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); - connect(newManager.data(), &ScriptManager::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); - connect(newManager.data(), &ScriptManager::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); - connect(newManager.data(), &ScriptManager::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); + connect(newManager.get(), &ScriptManager::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); + connect(newManager.get(), &ScriptManager::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); + connect(newManager.get(), &ScriptManager::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); + connect(newManager.get(), &ScriptManager::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); - connect(newManager.data(), &ScriptManager::update, this, [this] { + connect(newManager.get(), &ScriptManager::update, this, [this] { _entityViewer.queryOctree(); _entityViewer.getTree()->preUpdate(); _entityViewer.getTree()->update(); @@ -472,18 +472,18 @@ void EntityScriptServer::resetEntitiesScriptEngine() { scriptEngines->runScriptInitializers(newManager); newManager->runInThread(); - auto newEngineSP = qSharedPointerCast(newManager); + std::shared_ptr newEngineSP = newManager; // On the entity script server, these are the same DependencyManager::get()->setPersistentEntitiesScriptEngine(newEngineSP); DependencyManager::get()->setNonPersistentEntitiesScriptEngine(newEngineSP); if (_entitiesScriptManager) { - disconnect(_entitiesScriptManager.data(), &ScriptManager::entityScriptDetailsUpdated, + disconnect(_entitiesScriptManager.get(), &ScriptManager::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS); } _entitiesScriptManager.swap(newManager); - connect(_entitiesScriptManager.data(), &ScriptManager::entityScriptDetailsUpdated, + connect(_entitiesScriptManager.get(), &ScriptManager::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS); } @@ -516,7 +516,7 @@ void EntityScriptServer::shutdownScriptEngine() { auto scriptEngines = DependencyManager::get(); scriptEngines->shutdownScripting(); - _entitiesScriptManager.clear(); + _entitiesScriptManager.reset(); auto entityScriptingInterface = DependencyManager::get(); // our entity tree is going to go away so tell that to the EntityScriptingInterface diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index afa9e802fec..ae05a4a3a72 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7544,10 +7544,10 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptManage ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface(); scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); - connect(scriptManager.data(), &ScriptManager::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); + connect(scriptManager.get(), &ScriptManager::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); scriptEngine->registerGlobalObject("Overlays", &_overlays); - scriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue, + scriptRegisterMetaType(scriptEngine.get(), RayToOverlayIntersectionResultToScriptValue, RayToOverlayIntersectionResultFromScriptValue); bool clientScript = scriptManager->isClientScript(); @@ -7565,13 +7565,13 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptManage } #endif - scriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - scriptRegisterMetaType(scriptEngine.data(), + scriptRegisterMetaType(scriptEngine.get(), wrapperToScriptValue, wrapperFromScriptValue); + scriptRegisterMetaType(scriptEngine.get(), wrapperToScriptValue, wrapperFromScriptValue); scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get().data()); - scriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - scriptRegisterMetaType(scriptEngine.data(), + scriptRegisterMetaType(scriptEngine.get(), wrapperToScriptValue, wrapperFromScriptValue); + scriptRegisterMetaType(scriptEngine.get(), wrapperToScriptValue, wrapperFromScriptValue); scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); // FIXME remove these deprecated names for the tablet scripting interface @@ -7622,12 +7622,12 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptManage scriptEngine->registerGlobalObject("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED scriptEngine->registerGlobalObject("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED scriptEngine->registerGlobalObject("AccountServices", AccountServicesScriptingInterface::getInstance()); - scriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); + scriptRegisterMetaType(scriptEngine.get(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); scriptEngine->registerGlobalObject("AvatarManager", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LODManager", DependencyManager::get().data()); - scriptRegisterMetaType(scriptEngine.data(), worldDetailQualityToScriptValue, worldDetailQualityFromScriptValue); + scriptRegisterMetaType(scriptEngine.get(), worldDetailQualityToScriptValue, worldDetailQualityFromScriptValue); scriptEngine->registerGlobalObject("Keyboard", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Performance", new PerformanceScriptingInterface()); @@ -7642,7 +7642,7 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptManage scriptEngine->registerGlobalObject("Render", RenderScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Workload", _gameWorkload._engine->getConfiguration().get()); - GraphicsScriptingInterface::registerMetaTypes(scriptEngine.data()); + GraphicsScriptingInterface::registerMetaTypes(scriptEngine.get()); scriptEngine->registerGlobalObject("Graphics", DependencyManager::get().data()); scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get().data()); @@ -7654,11 +7654,11 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptManage scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { - scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptManager.data(), steamClient.get())); + scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptManager.get(), steamClient.get())); } auto scriptingInterface = DependencyManager::get(); scriptEngine->registerGlobalObject("Controller", scriptingInterface.data()); - UserInputMapper::registerControllerTypes(scriptEngine.data()); + UserInputMapper::registerControllerTypes(scriptEngine.get()); auto recordingInterface = DependencyManager::get(); scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); @@ -7674,18 +7674,18 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptManage scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance()); // Deprecated. scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get().data()); - registerInteractiveWindowMetaType(scriptEngine.data()); + registerInteractiveWindowMetaType(scriptEngine.get()); auto pickScriptingInterface = DependencyManager::get(); - pickScriptingInterface->registerMetaTypes(scriptEngine.data()); + pickScriptingInterface->registerMetaTypes(scriptEngine.get()); // connect this script engines printedMessage signal to the global ScriptEngines these various messages auto scriptEngines = DependencyManager::get().data(); - connect(scriptManager.data(), &ScriptManager::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); - connect(scriptManager.data(), &ScriptManager::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); - connect(scriptManager.data(), &ScriptManager::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); - connect(scriptManager.data(), &ScriptManager::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); - connect(scriptManager.data(), &ScriptManager::clearDebugWindow, scriptEngines, &ScriptEngines::onClearDebugWindow); + connect(scriptManager.get(), &ScriptManager::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); + connect(scriptManager.get(), &ScriptManager::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); + connect(scriptManager.get(), &ScriptManager::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); + connect(scriptManager.get(), &ScriptManager::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); + connect(scriptManager.get(), &ScriptManager::clearDebugWindow, scriptEngines, &ScriptEngines::onClearDebugWindow); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 679f3509bb2..b71248e2bb2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -14,6 +14,7 @@ #define hifi_Application_h #include +#include #include #include @@ -90,7 +91,7 @@ class AssetUpload; class CompositorHelper; class AudioInjector; class ScriptEngine; -using ScriptEnginePointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; namespace controller { class StateController; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d23e82cdf5f..13028822b71 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -448,8 +448,8 @@ void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) { } engine->globalObject().setProperty("DriveKeys", driveKeys); - scriptRegisterMetaType(engine.data(), audioListenModeToScriptValue, audioListenModeFromScriptValue); - scriptRegisterMetaType(engine.data(), driveKeysToScriptValue, driveKeysFromScriptValue); + scriptRegisterMetaType(engine.get(), audioListenModeToScriptValue, audioListenModeFromScriptValue); + scriptRegisterMetaType(engine.get(), driveKeysToScriptValue, driveKeysFromScriptValue); } void MyAvatar::setOrientationVar(const QVariant& newOrientationVar) { @@ -2669,7 +2669,7 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() { EntityItemProperties entityProperties = entity->getProperties(desiredProperties); { std::lock_guard guard(_scriptEngineLock); - ScriptValue scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties); + ScriptValue scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.get(), entityProperties); avatarEntityData["properties"] = scriptProperties.toVariant(); } avatarEntitiesData.append(QVariant(avatarEntityData)); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8008da631a4..425bcca3588 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -14,11 +14,11 @@ #define hifi_MyAvatar_h #include +#include #include #include -#include #include #include @@ -42,7 +42,7 @@ class ModelItemID; class MyHead; class DetailedMotionState; class ScriptEngine; -using ScriptEnginePointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; /*@jsdoc *

Locomotion control types.

diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 47105e0f3a2..78363b077d1 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -374,7 +374,7 @@ bool QmlCommerce::installApp(const QString& itemHref, const bool& alsoOpenImmedi // Don't try to re-load (install) a script if it's already running QStringList runningScripts = DependencyManager::get()->getRunningScripts(); if (!runningScripts.contains(scriptUrl)) { - if ((DependencyManager::get()->loadScript(scriptUrl.trimmed())).isNull()) { + if (!(DependencyManager::get()->loadScript(scriptUrl.trimmed()))) { qCDebug(commerce) << "Couldn't load script."; return false; } diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 71472d439ad..77b8af22e2c 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -308,7 +308,7 @@ void JSConsole::highlightedCompletion(const QModelIndex& completion) { JSConsole::~JSConsole() { if (_scriptManager) { - disconnect(_scriptManager.data(), nullptr, this, nullptr); + disconnect(_scriptManager.get(), nullptr, this, nullptr); _scriptManager.reset(); } delete _ui; @@ -319,21 +319,21 @@ void JSConsole::setScriptManager(const ScriptManagerPointer& scriptManager) { return; } if (scriptManager != nullptr) { - disconnect(_scriptManager.data(), nullptr, this, nullptr); + disconnect(_scriptManager.get(), nullptr, this, nullptr); _scriptManager.reset(); } // if scriptEngine is nullptr then create one and keep track of it using _ownScriptEngine - if (scriptManager.isNull()) { + if (!scriptManager) { _scriptManager = DependencyManager::get()->loadScript(_consoleFileName, false); } else { _scriptManager = scriptManager; } - connect(_scriptManager.data(), &ScriptManager::printedMessage, this, &JSConsole::handlePrint); - connect(_scriptManager.data(), &ScriptManager::infoMessage, this, &JSConsole::handleInfo); - connect(_scriptManager.data(), &ScriptManager::warningMessage, this, &JSConsole::handleWarning); - connect(_scriptManager.data(), &ScriptManager::errorMessage, this, &JSConsole::handleError); + connect(_scriptManager.get(), &ScriptManager::printedMessage, this, &JSConsole::handlePrint); + connect(_scriptManager.get(), &ScriptManager::infoMessage, this, &JSConsole::handleInfo); + connect(_scriptManager.get(), &ScriptManager::warningMessage, this, &JSConsole::handleWarning); + connect(_scriptManager.get(), &ScriptManager::errorMessage, this, &JSConsole::handleError); } void JSConsole::executeCommand(const QString& command) { @@ -349,13 +349,13 @@ void JSConsole::executeCommand(const QString& command) { appendMessage(">", "" + command.toHtmlEscaped() + ""); - QWeakPointer weakScriptManager = _scriptManager; + std::weak_ptr weakScriptManager = _scriptManager; auto consoleFileName = _consoleFileName; QFuture future = QtConcurrent::run([weakScriptManager, consoleFileName, command]() -> ScriptValue { ScriptValue result; auto scriptManager = weakScriptManager.lock(); if (scriptManager) { - BLOCKING_INVOKE_METHOD(scriptManager.data(), "evaluate", + BLOCKING_INVOKE_METHOD(scriptManager.get(), "evaluate", Q_RETURN_ARG(ScriptValue, result), Q_ARG(const QString&, command), Q_ARG(const QString&, consoleFileName)); diff --git a/interface/src/ui/JSConsole.h b/interface/src/ui/JSConsole.h index 73ca86c5b7b..4bfa4cb107d 100644 --- a/interface/src/ui/JSConsole.h +++ b/interface/src/ui/JSConsole.h @@ -12,9 +12,10 @@ #ifndef hifi_JSConsole_h #define hifi_JSConsole_h +#include + #include #include -#include #include #include #include @@ -23,7 +24,7 @@ class QStandardItemModel; class ScriptManager; -using ScriptManagerPointer = QSharedPointer; +using ScriptManagerPointer = std::shared_ptr; const QString CONSOLE_TITLE = "Scripting Console"; const float CONSOLE_WINDOW_OPACITY = 0.95f; diff --git a/interface/src/ui/TestingDialog.cpp b/interface/src/ui/TestingDialog.cpp index c357820cf35..49653c032f7 100644 --- a/interface/src/ui/TestingDialog.cpp +++ b/interface/src/ui/TestingDialog.cpp @@ -26,7 +26,7 @@ TestingDialog::TestingDialog(QWidget* parent) : _manager = DependencyManager::get()->loadScript(qApp->applicationDirPath() + testRunnerRelativePath); _console->setScriptManager(_manager); - connect(_manager.data(), &ScriptManager::finished, this, &TestingDialog::onTestingFinished); + connect(_manager.get(), &ScriptManager::finished, this, &TestingDialog::onTestingFinished); } void TestingDialog::onTestingFinished(const QString& scriptPath) { diff --git a/interface/src/ui/TestingDialog.h b/interface/src/ui/TestingDialog.h index 968188fbca4..21977373253 100644 --- a/interface/src/ui/TestingDialog.h +++ b/interface/src/ui/TestingDialog.h @@ -12,12 +12,13 @@ #ifndef hifi_TestingDialog_h #define hifi_TestingDialog_h +#include + #include -#include #include "JSConsole.h" class ScriptManager; -using ScriptManagerPointer = QSharedPointer; +using ScriptManagerPointer = std::shared_ptr; const QString windowLabel = "Client Script Tests"; const QString testRunnerRelativePath = "/scripts/developer/tests/unit_tests/testRunner.js"; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index a2f774e77a0..72e2748daf4 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -641,7 +641,7 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemProperties& properties) { ScriptEnginePointer scriptEngine = newScriptEngine(); - QVariantMap overlayProps = EntityItemPropertiesToScriptValue(scriptEngine.data(), properties).toVariant().toMap(); + QVariantMap overlayProps = EntityItemPropertiesToScriptValue(scriptEngine.get(), properties).toVariant().toMap(); QString type = overlayProps["type"].toString(); overlayProps["type"] = entityToOverlayType(type); diff --git a/libraries/animation/src/AnimationObject.cpp b/libraries/animation/src/AnimationObject.cpp index 09ac8114b9a..6782768f5b4 100644 --- a/libraries/animation/src/AnimationObject.cpp +++ b/libraries/animation/src/AnimationObject.cpp @@ -19,7 +19,7 @@ #include "AnimationCache.h" STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - registerAnimationTypes(manager->engine().data()); + registerAnimationTypes(manager->engine().get()); }); QStringList AnimationObject::getJointNames() const { diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 8edddd9092e..2c9c9462021 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -16,7 +16,7 @@ #include STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine(); ScriptValue audioEffectOptionsConstructorValue = scriptEngine->newFunction(AudioEffectOptions::constructor); scriptEngine->globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index f84efada047..ec7a50e5df1 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -23,7 +23,7 @@ STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager){ - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine().get(); registerAudioMetaTypes(scriptEngine); scriptEngine->registerGlobalObject("Audio", DependencyManager::get().data()); diff --git a/libraries/audio/src/ScriptAudioInjector.cpp b/libraries/audio/src/ScriptAudioInjector.cpp index d50bf6f163c..09f24c72077 100644 --- a/libraries/audio/src/ScriptAudioInjector.cpp +++ b/libraries/audio/src/ScriptAudioInjector.cpp @@ -18,7 +18,7 @@ #include STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine().get(); scriptRegisterMetaType(scriptEngine, injectorToScriptValue, injectorFromScriptValue); }); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 184f1bf7048..b7683e34aba 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -68,7 +68,7 @@ static const float DEFAULT_AVATAR_DENSITY = 1000.0f; // density of water #define ASSERT(COND) do { if (!(COND)) { abort(); } } while(0) STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine().get(); registerAvatarTypes(scriptEngine); scriptRegisterMetaType(scriptEngine, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue); diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index 5b33f53cd56..9f23fee84a9 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -25,7 +25,7 @@ void avatarDataFromScriptValue(const ScriptValue& object, ScriptAvatarData*& out } STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine().get(); scriptRegisterMetaType(scriptEngine, avatarDataToScriptValue, avatarDataFromScriptValue); }); diff --git a/libraries/baking/src/MaterialBaker.cpp b/libraries/baking/src/MaterialBaker.cpp index 7922137a056..022e468df7e 100644 --- a/libraries/baking/src/MaterialBaker.cpp +++ b/libraries/baking/src/MaterialBaker.cpp @@ -212,13 +212,15 @@ void MaterialBaker::outputMaterial() { if (_materialResource->parsedMaterials.networkMaterials.size() == 1) { auto networkMaterial = _materialResource->parsedMaterials.networkMaterials.begin(); auto scriptableMaterial = scriptable::ScriptableMaterial(networkMaterial->second); - QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(_scriptEngine.data(), scriptableMaterial).toVariant(); + QVariant materialVariant = + scriptable::scriptableMaterialToScriptValue(_scriptEngine.get(), scriptableMaterial).toVariant(); json.insert("materials", QJsonDocument::fromVariant(materialVariant).object()); } else { QJsonArray materialArray; for (auto networkMaterial : _materialResource->parsedMaterials.networkMaterials) { auto scriptableMaterial = scriptable::ScriptableMaterial(networkMaterial.second); - QVariant materialVariant = scriptable::scriptableMaterialToScriptValue(_scriptEngine.data(), scriptableMaterial).toVariant(); + QVariant materialVariant = + scriptable::scriptableMaterialToScriptValue(_scriptEngine.get(), scriptableMaterial).toVariant(); materialArray.append(QJsonDocument::fromVariant(materialVariant).object()); } json.insert("materials", materialArray); diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index 9e538b999b7..b6e57a0c4e1 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -42,7 +42,7 @@ void inputControllerFromScriptValue(const ScriptValue& object, controller::Input } STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine().get(); scriptRegisterMetaType(scriptEngine, inputControllerToScriptValue, inputControllerFromScriptValue); }); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4662fa2ad06..b9014c5be80 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -161,42 +161,52 @@ int EntityTreeRenderer::_entitiesScriptEngineCount = 0; void EntityTreeRenderer::setupEntityScriptEngineSignals(const ScriptManagerPointer& scriptManager) { auto entityScriptingInterface = DependencyManager::get(); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "mousePressOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseDoublePressOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseDoublePressOnEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "mouseDoublePressOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "mouseMoveOnEntity", event); // FIXME: this is a duplicate of mouseMoveOnEntity, but it seems like some scripts might use this naming scriptManager->callEntityScriptMethod(entityID, "mouseMoveEvent", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "mouseReleaseOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "clickDownOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::holdingClickOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::holdingClickOnEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "holdingClickOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickReleaseOnEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickReleaseOnEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "clickReleaseOnEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "hoverEnterEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "hoverOverEntity", event); }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, scriptManager.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, scriptManager.get(), + [&](const EntityItemID& entityID, const PointerEvent& event) { scriptManager->callEntityScriptMethod(entityID, "hoverLeaveEntity", event); }); - connect(scriptManager.data(), &ScriptManager::entityScriptPreloadFinished, [&](const EntityItemID& entityID) { + connect(scriptManager.get(), &ScriptManager::entityScriptPreloadFinished, [&](const EntityItemID& entityID) { EntityItemPointer entity = getTree()->findEntityByID(entityID); if (entity) { entity->setScriptHasFinishedPreload(true); @@ -215,7 +225,7 @@ void EntityTreeRenderer::resetPersistentEntitiesScriptEngine() { QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); DependencyManager::get()->runScriptInitializers(_persistentEntitiesScriptManager); _persistentEntitiesScriptManager->runInThread(); - auto entitiesScriptEngineProvider = qSharedPointerCast(_persistentEntitiesScriptManager); + std::shared_ptr entitiesScriptEngineProvider = _persistentEntitiesScriptManager; auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->setPersistentEntitiesScriptEngine(entitiesScriptEngineProvider); @@ -233,7 +243,7 @@ void EntityTreeRenderer::resetNonPersistentEntitiesScriptEngine() { QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); DependencyManager::get()->runScriptInitializers(_nonPersistentEntitiesScriptManager); _nonPersistentEntitiesScriptManager->runInThread(); - auto entitiesScriptEngineProvider = qSharedPointerCast(_nonPersistentEntitiesScriptManager); + std::shared_ptr entitiesScriptEngineProvider = _nonPersistentEntitiesScriptManager; DependencyManager::get()->setNonPersistentEntitiesScriptEngine(entitiesScriptEngineProvider); setupEntityScriptEngineSignals(_nonPersistentEntitiesScriptManager); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index f4fdc222e8a..d24acb01421 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -12,6 +12,8 @@ #ifndef hifi_EntityTreeRenderer_h #define hifi_EntityTreeRenderer_h +#include + #include #include #include @@ -35,8 +37,8 @@ class ZoneEntityItem; class EntityItem; class ScriptEngine; class ScriptManager; -using ScriptEnginePointer = QSharedPointer; -using ScriptManagerPointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; +using ScriptManagerPointer = std::shared_ptr; namespace render { namespace entities { class EntityRenderer; diff --git a/libraries/entities-renderer/src/ModelScriptingInterface.cpp b/libraries/entities-renderer/src/ModelScriptingInterface.cpp index 7b87c50619d..d08eb3f75e1 100644 --- a/libraries/entities-renderer/src/ModelScriptingInterface.cpp +++ b/libraries/entities-renderer/src/ModelScriptingInterface.cpp @@ -19,7 +19,7 @@ #include STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine(); scriptEngine->registerGlobalObject("Model", new ModelScriptingInterface(manager)); }); diff --git a/libraries/entities-renderer/src/ModelScriptingInterface.h b/libraries/entities-renderer/src/ModelScriptingInterface.h index 70ac4fae9a4..9bc5529a5ad 100644 --- a/libraries/entities-renderer/src/ModelScriptingInterface.h +++ b/libraries/entities-renderer/src/ModelScriptingInterface.h @@ -15,14 +15,15 @@ #ifndef hifi_ModelScriptingInterface_h #define hifi_ModelScriptingInterface_h +#include + #include -#include #include #include class ScriptEngine; -using ScriptEnginePointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; /*@jsdoc * The Model API provides the ability to manipulate meshes. You can get the meshes for an entity using @@ -101,7 +102,7 @@ class ModelScriptingInterface : public QObject { Q_INVOKABLE ScriptValue getVertex(MeshProxy* meshProxy, int vertexIndex); private: - ScriptEnginePointer _modelScriptEngine { nullptr }; + ScriptEnginePointer _modelScriptEngine; }; #endif // hifi_ModelScriptingInterface_h diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 6901b0b1641..563f62d3802 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -264,7 +264,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { engine->setProperty("fileName", urlString); engine->setProperty("entityID", entityID); engine->globalObject().setProperty("Script", engine->newQObject(manager.get())); - DependencyManager::get()->runScriptInitializers(engine.data()); + DependencyManager::get()->runScriptInitializers(engine.get()); engine->evaluate(scriptContents, urlString); if (!hadUncaughtExceptions(*engine, urlString)) { // put the engine in the engine map (so we don't leak them, etc...) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8d0b5daee31..8ed610dc691 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -49,7 +49,7 @@ const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}"; const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}"; void staticEntityScriptInitializer(ScriptManager* manager) { - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine().get(); auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->init(); @@ -145,7 +145,8 @@ void EntityScriptingInterface::attachDefaultEventHandlers(ScriptManager* manager using SingleEntityHandler = std::function; auto makeSingleEntityHandler = [manager](QString eventName) -> SingleEntityHandler { return [manager, eventName](const EntityItemID& entityItemID) { - manager->forwardHandlerCall(entityItemID, eventName, { EntityItemIDtoScriptValue(manager->engine().data(), entityItemID) }); + manager->forwardHandlerCall(entityItemID, eventName, + { EntityItemIDtoScriptValue(manager->engine().get(), entityItemID) }); }; }; @@ -159,7 +160,7 @@ void EntityScriptingInterface::attachDefaultEventHandlers(ScriptManager* manager auto makePointerHandler = [manager](QString eventName) -> PointerHandler { return [manager, eventName](const EntityItemID& entityItemID, const PointerEvent& event) { if (!EntityTree::areEntityClicksCaptured()) { - ScriptEngine* engine = manager->engine().data(); + ScriptEngine* engine = manager->engine().get(); manager->forwardHandlerCall(entityItemID, eventName, { EntityItemIDtoScriptValue(engine, entityItemID), event.toScriptValue(engine) }); } @@ -176,7 +177,7 @@ void EntityScriptingInterface::attachDefaultEventHandlers(ScriptManager* manager using CollisionHandler = std::function; auto makeCollisionHandler = [manager](QString eventName) -> CollisionHandler { return [manager, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - ScriptEngine* engine = manager->engine().data(); + ScriptEngine* engine = manager->engine().get(); manager->forwardHandlerCall(idA, eventName, { EntityItemIDtoScriptValue(engine, idA), EntityItemIDtoScriptValue(engine, idB), @@ -1234,12 +1235,12 @@ QSizeF EntityScriptingInterface::textSize(const QUuid& id, const QString& text) return EntityTree::textSize(id, text); } -void EntityScriptingInterface::setPersistentEntitiesScriptEngine(QSharedPointer manager) { +void EntityScriptingInterface::setPersistentEntitiesScriptEngine(std::shared_ptr manager) { std::lock_guard lock(_entitiesScriptEngineLock); _persistentEntitiesScriptManager = manager; } -void EntityScriptingInterface::setNonPersistentEntitiesScriptEngine(QSharedPointer manager) { +void EntityScriptingInterface::setNonPersistentEntitiesScriptEngine(std::shared_ptr manager) { std::lock_guard lock(_entitiesScriptEngineLock); _nonPersistentEntitiesScriptManager = manager; } @@ -1528,7 +1529,7 @@ bool EntityPropertyMetadataRequest::script(EntityItemID entityID, const ScriptVa request->deleteLater(); }); auto entityScriptingInterface = DependencyManager::get(); - entityScriptingInterface->withEntitiesScriptEngine([&](QSharedPointer entitiesScriptEngine) { + entityScriptingInterface->withEntitiesScriptEngine([&](std::shared_ptr entitiesScriptEngine) { if (entitiesScriptEngine) { request->setFuture(entitiesScriptEngine->getLocalEntityScriptDetails(entityID)); } @@ -2442,7 +2443,7 @@ void EntityScriptingInterface::getMeshes(const QUuid& entityID, const ScriptValu bool success = entity->getMeshes(result); if (success) { - ScriptValue resultAsScriptValue = meshesToScriptValue(engine.data(), result); + ScriptValue resultAsScriptValue = meshesToScriptValue(engine.get(), result); ScriptValueList args{ resultAsScriptValue, engine->newValue(true) }; callback.call(ScriptValue(), args); } else { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 36fe1962c84..774228cfdc7 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -15,6 +15,8 @@ #ifndef hifi_EntityScriptingInterface_h #define hifi_EntityScriptingInterface_h +#include + #include #include #include @@ -184,8 +186,8 @@ class EntityScriptingInterface : public OctreeScriptingInterface, public Depende void setEntityTree(EntityTreePointer modelTree); EntityTreePointer getEntityTree() { return _entityTree; } - void setPersistentEntitiesScriptEngine(QSharedPointer manager); - void setNonPersistentEntitiesScriptEngine(QSharedPointer manager); + void setPersistentEntitiesScriptEngine(std::shared_ptr manager); + void setNonPersistentEntitiesScriptEngine(std::shared_ptr manager); void resetActivityTracking(); ActivityTracking getActivityTracking() const { return _activityTracking; } @@ -2531,7 +2533,7 @@ public slots: void webEventReceived(const EntityItemID& entityItemID, const QVariant& message); protected: - void withEntitiesScriptEngine(std::function)> function, const EntityItemID& id) { + void withEntitiesScriptEngine(std::function)> function, const EntityItemID& id) { auto entity = getEntityTree()->findEntityByEntityItemID(id); if (entity) { std::lock_guard lock(_entitiesScriptEngineLock); @@ -2572,8 +2574,8 @@ private slots: EntityTreePointer _entityTree; std::recursive_mutex _entitiesScriptEngineLock; - QSharedPointer _persistentEntitiesScriptManager; - QSharedPointer _nonPersistentEntitiesScriptManager; + std::shared_ptr _persistentEntitiesScriptManager; + std::shared_ptr _nonPersistentEntitiesScriptManager; bool _bidOnSimulationOwnership { false }; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 53724920361..0bb59095a59 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2943,7 +2943,7 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer entityDescription["DataVersion"] = _persistDataVersion; entityDescription["Id"] = _persistID; ScriptEnginePointer engine = newScriptEngine(); - RecurseOctreeToMapOperator theOperator(entityDescription, element, engine.data(), skipDefaultValues, + RecurseOctreeToMapOperator theOperator(entityDescription, element, engine.get(), skipDefaultValues, skipThoseWithBadParents, _myAvatar); withReadLock([&] { recurseTreeWithOperator(&theOperator); @@ -3268,7 +3268,7 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { bool EntityTree::writeToJSON(QString& jsonString, const OctreeElementPointer& element) { ScriptEnginePointer engine = newScriptEngine(); - RecurseOctreeToJSONOperator theOperator(element, engine.data(), jsonString); + RecurseOctreeToJSONOperator theOperator(element, engine.get(), jsonString); withReadLock([&] { recurseTreeWithOperator(&theOperator); }); diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index c9b7b348a86..d88f31394e7 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -135,7 +135,7 @@ void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD } STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - auto scriptEngine = manager->engine().data(); + auto scriptEngine = manager->engine(); scriptEngine->registerGlobalObject("Midi", DependencyManager::get().data()); }); diff --git a/libraries/script-engine/src/AbstractScriptingServicesInterface.h b/libraries/script-engine/src/AbstractScriptingServicesInterface.h index 2e96924ab67..5c99240e906 100644 --- a/libraries/script-engine/src/AbstractScriptingServicesInterface.h +++ b/libraries/script-engine/src/AbstractScriptingServicesInterface.h @@ -15,10 +15,10 @@ #ifndef hifi_AbstractScriptingServicesInterface_h #define hifi_AbstractScriptingServicesInterface_h -#include +#include class ScriptManager; -using ScriptManagerPointer = QSharedPointer; +using ScriptManagerPointer = std::shared_ptr; /// Interface provided by Application to other objects that need access to scripting services of the application class AbstractScriptingServicesInterface { diff --git a/libraries/script-engine/src/ScriptContext.h b/libraries/script-engine/src/ScriptContext.h index 9a38a67c71d..e046fe88ca0 100644 --- a/libraries/script-engine/src/ScriptContext.h +++ b/libraries/script-engine/src/ScriptContext.h @@ -15,7 +15,8 @@ #ifndef hifi_ScriptContext_h #define hifi_ScriptContext_h -#include +#include + #include #include @@ -24,9 +25,9 @@ class ScriptContext; class ScriptEngine; class ScriptFunctionContext; -using ScriptContextPointer = QSharedPointer; -using ScriptFunctionContextPointer = QSharedPointer; -using ScriptEnginePointer = QSharedPointer; +using ScriptContextPointer = std::shared_ptr; +using ScriptFunctionContextPointer = std::shared_ptr; +using ScriptEnginePointer = std::shared_ptr; /// [ScriptInterface] Provides an engine-independent interface for QScriptContextInfo class ScriptFunctionContext { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index fa791709d47..4bcac85e45a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -17,7 +17,7 @@ #include "qtscript/ScriptEngineQtScript.h" ScriptEnginePointer newScriptEngine(ScriptManager* manager) { - return QSharedPointer(new ScriptEngineQtScript(manager)); + return std::make_shared(manager); } ScriptValue makeScopedHandlerObject(const ScriptValue& scopeOrCallback, const ScriptValue& methodOrName) { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index d7729ce75fb..c69a0af8c31 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -16,9 +16,10 @@ #ifndef hifi_ScriptEngine_h #define hifi_ScriptEngine_h +#include + #include #include -#include #include "ScriptValue.h" @@ -31,8 +32,8 @@ class ScriptContext; class ScriptEngine; class ScriptManager; class ScriptProgram; -using ScriptEnginePointer = QSharedPointer; -using ScriptProgramPointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; +using ScriptProgramPointer = std::shared_ptr; Q_DECLARE_METATYPE(ScriptEnginePointer); diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index a1b524441fc..c24dae6ba0c 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -421,7 +421,7 @@ void ScriptEngines::stopAllScripts(bool restart) { _isReloading = true; ScriptManager::Type type = scriptManager->getType(); - connect(scriptManager.data(), &ScriptManager::finished, this, [this, type, isOverrideScript](QString scriptName) { + connect(scriptManager.get(), &ScriptManager::finished, this, [this, type, isOverrideScript](QString scriptName) { reloadScript(scriptName, !isOverrideScript)->setType(type); }); } @@ -457,7 +457,7 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { scriptCache->deleteScript(scriptURL); if (!scriptManager->isStopping()) { - connect(scriptManager.data(), &ScriptManager::finished, + connect(scriptManager.get(), &ScriptManager::finished, this, [this, isUserLoaded, type](QString scriptName, ScriptManagerPointer manager) { reloadScript(scriptName, isUserLoaded)->setType(type); }); @@ -522,12 +522,12 @@ ScriptManagerPointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool launchScriptEngine(scriptManager); } else { // connect to the appropriate signals of this script engine - connect(scriptManager.data(), &ScriptManager::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded); - connect(scriptManager.data(), &ScriptManager::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); + connect(scriptManager.get(), &ScriptManager::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded); + connect(scriptManager.get(), &ScriptManager::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); // Shutdown Interface when script finishes, if requested if (quitWhenFinished) { - connect(scriptManager.data(), &ScriptManager::finished, this, &ScriptEngines::quitWhenFinished); + connect(scriptManager.get(), &ScriptManager::finished, this, &ScriptEngines::quitWhenFinished); } // get the script engine object to load the script at the designated script URL @@ -553,7 +553,7 @@ ScriptManagerPointer ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { // FIXME - change to new version of ScriptCache loading notification void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { UserActivityLogger::getInstance().loadedScript(rawScriptURL); - ScriptManagerPointer scriptEngine = qobject_cast(sender())->sharedFromThis(); + ScriptManagerPointer scriptEngine = qobject_cast(sender())->shared_from_this(); launchScriptEngine(scriptEngine); @@ -574,16 +574,18 @@ void ScriptEngines::quitWhenFinished() { } int ScriptEngines::runScriptInitializers(ScriptManagerPointer scriptManager) { - auto nativeCount = DependencyManager::get()->runScriptInitializers(scriptManager->engine().data()); + auto nativeCount = DependencyManager::get()->runScriptInitializers(scriptManager->engine().get()); return nativeCount + ScriptInitializerMixin::runScriptInitializers(scriptManager); } void ScriptEngines::launchScriptEngine(ScriptManagerPointer scriptManager) { - connect(scriptManager.data(), &ScriptManager::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection); - connect(scriptManager.data(), &ScriptManager::loadScript, [this](const QString& scriptName, bool userLoaded) { + connect(scriptManager.get(), &ScriptManager::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection); + connect(scriptManager.get(), &ScriptManager::loadScript, + [this](const QString& scriptName, bool userLoaded) { loadScript(scriptName, userLoaded); }); - connect(scriptManager.data(), &ScriptManager::reloadScript, [this](const QString& scriptName, bool userLoaded) { + connect(scriptManager.get(), &ScriptManager::reloadScript, + [this](const QString& scriptName, bool userLoaded) { loadScript(scriptName, userLoaded, false, false, true); }); diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 98b7ef16e8e..af9e8736e0d 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 44394d9733c..09f92eeec09 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -133,7 +133,7 @@ static ScriptValue debugPrint(ScriptContext* context, ScriptEngine* engine) { ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan while (userContext && userContext->functionContext()->functionType() == ScriptFunctionContext::NativeFunction) { parentContext = userContext->parentContext(); - userContext = parentContext.data(); + userContext = parentContext.get(); } QString location; if (userContext) { @@ -211,7 +211,8 @@ ScriptManagerPointer scriptManagerFactory(ScriptManager::Context context, ScriptManagerPointer newScriptManager(ScriptManager::Context context, const QString& scriptContents, const QString& fileNameString) { - ScriptManagerPointer manager(new ScriptManager(context, scriptContents, fileNameString), &QObject::deleteLater); + ScriptManagerPointer manager(new ScriptManager(context, scriptContents, fileNameString), + [](ScriptManager* obj) { obj->deleteLater(); }); ScriptEnginePointer engine = newScriptEngine(manager.get()); manager->_engine = engine; return manager; @@ -559,7 +560,7 @@ static ScriptValue createScriptableResourcePrototype(ScriptManagerPointer manage auto prototype = engine->newObject(); // Expose enum State to JS/QML via properties - QObject* state = new QObject(manager.data()); + QObject* state = new QObject(manager.get()); state->setObjectName("ResourceState"); auto metaEnum = QMetaEnum::fromType(); for (int i = 0; i < metaEnum.keyCount(); ++i) { @@ -623,7 +624,7 @@ void ScriptManager::init() { _isInitialized = true; runStaticInitializers(this); - auto scriptEngine = _engine.data(); + auto scriptEngine = _engine.get(); // register various meta-types registerMIDIMetaTypes(scriptEngine); @@ -693,7 +694,7 @@ void ScriptManager::init() { scriptEngine->registerFunction("console", "groupEnd", ConsoleScriptingInterface::groupEnd, 0); // Scriptable cache access - auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast(sharedFromThis())); + auto resourcePrototype = createScriptableResourcePrototype(shared_from_this()); scriptEngine->globalObject().setProperty("Resource", resourcePrototype); scriptEngine->setDefaultPrototype(qMetaTypeId(), resourcePrototype); scriptRegisterMetaType(scriptEngine, scriptableResourceToScriptValue, scriptableResourceFromScriptValue); @@ -960,7 +961,7 @@ void ScriptManager::run() { emit releaseEntityPacketSenderMessages(true); - emit finished(_fileNameString, qSharedPointerCast(sharedFromThis())); + emit finished(_fileNameString, shared_from_this()); // Don't leave our local-file-access flag laying around, reset it to false when the scriptengine // thread is finished @@ -1117,7 +1118,7 @@ QUrl ScriptManager::resolvePath(const QString& include) const { auto contextInfo = context->functionContext(); parentURL = QUrl(contextInfo->fileName()); parentContext = context->parentContext(); - context = parentContext.data(); + context = parentContext.get(); } while (parentURL.isRelative() && context); if (parentURL.isRelative()) { @@ -1258,7 +1259,8 @@ ScriptValue ScriptManager::currentModule() { auto cache = jsRequire.property("cache"); ScriptValue candidate; ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan - for (auto context = _engine->currentContext(); context && !candidate.isObject(); parentContext = context->parentContext(), context = parentContext.data()) { + for (auto context = _engine->currentContext(); context && !candidate.isObject(); + parentContext = context->parentContext(), context = parentContext.get()) { auto contextInfo = context->functionContext(); candidate = cache.property(contextInfo->fileName()); } @@ -1808,10 +1810,10 @@ void ScriptManager::loadEntityScript(const EntityItemID& entityID, const QString auto scriptCache = DependencyManager::get(); // note: see EntityTreeRenderer.cpp for shared pointer lifecycle management - QWeakPointer weakRef(sharedFromThis()); + std::weak_ptr weakRef(shared_from_this()); scriptCache->getScriptContents(entityScript, [this, weakRef, entityScript, entityID](const QString& url, const QString& contents, bool isURL, bool success, const QString& status) { - QSharedPointer strongRef(weakRef); + std::shared_ptr strongRef(weakRef); if (!strongRef) { qCWarning(scriptengine) << "loadEntityScript.contentAvailable -- ScriptManager was deleted during getScriptContents!!"; return; @@ -1929,7 +1931,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c return; } auto program = _engine->newProgram( contents, fileName ); - if (program.isNull()) { + if (!program) { setError("Bad program (isNull)", EntityScriptStatus::ERROR_RUNNING_SCRIPT); emit unhandledException(_engine->makeError(_engine->newValue("program.isNull"))); return; // done processing script @@ -2337,7 +2339,7 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q } if (callAllowed && entityScript.property(methodName).isFunction()) { - auto scriptEngine = engine().data(); + auto scriptEngine = engine().get(); ScriptValueList args; args << EntityItemIDtoScriptValue(scriptEngine, entityID); @@ -2380,7 +2382,7 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q } ScriptValue entityScript = details.scriptObject; // previously loaded if (entityScript.property(methodName).isFunction()) { - auto scriptEngine = engine().data(); + auto scriptEngine = engine().get(); ScriptValueList args; args << EntityItemIDtoScriptValue(scriptEngine, entityID); @@ -2420,7 +2422,7 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q } ScriptValue entityScript = details.scriptObject; // previously loaded if (entityScript.property(methodName).isFunction()) { - auto scriptEngine = engine().data(); + auto scriptEngine = engine().get(); ScriptValueList args; args << EntityItemIDtoScriptValue(scriptEngine, entityID); diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index 7723c9b7be1..ea0a33a1520 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -19,10 +19,10 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -57,8 +57,8 @@ static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900; class ScriptEngine; class ScriptEngines; class ScriptManager; -using ScriptEnginePointer = QSharedPointer; -using ScriptManagerPointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; +using ScriptManagerPointer = std::shared_ptr; using ScriptValueList = QList; Q_DECLARE_METATYPE(ScriptManagerPointer) @@ -141,7 +141,7 @@ class EntityScriptDetails { * @property {Script.ResourceBuckets} ExternalPaths - External resource buckets. */ /// The main class managing a scripting engine. Also provides the Script scripting interface -class ScriptManager : public QObject, public EntitiesScriptEngineProvider, public QEnableSharedFromThis { +class ScriptManager : public QObject, public EntitiesScriptEngineProvider, public std::enable_shared_from_this { Q_OBJECT Q_PROPERTY(QString context READ getContext) Q_PROPERTY(QString type READ getTypeAsString) diff --git a/libraries/script-engine/src/ScriptProgram.h b/libraries/script-engine/src/ScriptProgram.h index abfe0d2748c..ae26abace66 100644 --- a/libraries/script-engine/src/ScriptProgram.h +++ b/libraries/script-engine/src/ScriptProgram.h @@ -15,12 +15,12 @@ #ifndef hifi_ScriptProgram_h #define hifi_ScriptProgram_h -#include +#include class ScriptProgram; class ScriptSyntaxCheckResult; -using ScriptProgramPointer = QSharedPointer; -using ScriptSyntaxCheckResultPointer = QSharedPointer; +using ScriptProgramPointer = std::shared_ptr; +using ScriptSyntaxCheckResultPointer = std::shared_ptr; /// [ScriptInterface] Provides an engine-independent interface for QScriptProgram class ScriptProgram { diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h index bafbf349f1a..d5a057e0ad0 100644 --- a/libraries/script-engine/src/ScriptValue.h +++ b/libraries/script-engine/src/ScriptValue.h @@ -15,10 +15,11 @@ #ifndef hifi_ScriptValue_h #define hifi_ScriptValue_h +#include + #include #include #include -#include #include #include @@ -26,9 +27,9 @@ class ScriptEngine; class ScriptValue; class ScriptValueIterator; class ScriptValueProxy; -using ScriptEnginePointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; using ScriptValueList = QList; -using ScriptValueIteratorPointer = QSharedPointer; +using ScriptValueIteratorPointer = std::shared_ptr; /// [ScriptInterface] Provides an engine-independent interface for QScriptValue class ScriptValue { diff --git a/libraries/script-engine/src/ScriptValueIterator.h b/libraries/script-engine/src/ScriptValueIterator.h index 13ae8be74e6..657bef6fbbf 100644 --- a/libraries/script-engine/src/ScriptValueIterator.h +++ b/libraries/script-engine/src/ScriptValueIterator.h @@ -15,13 +15,14 @@ #ifndef hifi_ScriptValueIterator_h #define hifi_ScriptValueIterator_h -#include +#include + #include #include "ScriptValue.h" class ScriptValueIterator; -using ScriptValueIteratorPointer = QSharedPointer; +using ScriptValueIteratorPointer = std::shared_ptr; /// [ScriptInterface] Provides an engine-independent interface for QScriptValueIterator class ScriptValueIterator { diff --git a/libraries/script-engine/src/Scriptable.h b/libraries/script-engine/src/Scriptable.h index 39d5974168a..45669a111cc 100644 --- a/libraries/script-engine/src/Scriptable.h +++ b/libraries/script-engine/src/Scriptable.h @@ -15,13 +15,13 @@ #ifndef hifi_Scriptable_h #define hifi_Scriptable_h -#include +#include #include "ScriptContext.h" #include "ScriptValue.h" class ScriptEngine; -using ScriptEnginePointer = QSharedPointer; +using ScriptEnginePointer = std::shared_ptr; /// [ScriptInterface] Provides an engine-independent interface for QScriptable class Scriptable { diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp index db888c3e99d..e082272a630 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp @@ -21,7 +21,7 @@ void ScriptContextQtAgent::contextPop() { if (_prevAgent) { _prevAgent->contextPop(); } - if (_engine->currentContext() == _currContext) { + if (_engine->currentContext() == _currContext.get()) { _currContext.reset(); if (!_contextActive && !_contextStack.empty()) { _currContext = _contextStack.back(); @@ -50,7 +50,7 @@ void ScriptContextQtAgent::functionEntry(qint64 scriptId) { return; } if (!_currContext) { - _currContext = ScriptContextQtPointer(new ScriptContextQtWrapper(_engine, static_cast(_engine)->currentContext())); + _currContext = std::make_shared(_engine, static_cast(_engine)->currentContext()); } Scriptable::setContext(_currContext.get()); _contextActive = true; diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h index 38e64ffc221..f23d82dc2bc 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h @@ -12,8 +12,9 @@ #ifndef hifi_ScriptContextQtAgent_h #define hifi_ScriptContextQtAgent_h +#include + #include -#include #include #include "ScriptEngineQtScript.h" @@ -22,7 +23,7 @@ class QScriptContext; class QScriptValue; class ScriptContextQtWrapper; class ScriptEngineQtScript; -using ScriptContextQtPointer = QSharedPointer; +using ScriptContextQtPointer = std::shared_ptr; class ScriptContextQtAgent final : public QScriptEngineAgent { public: // construction diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp index 75172bed12e..72f6ea41b13 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp @@ -43,16 +43,16 @@ ScriptValue ScriptContextQtWrapper::callee() const { } ScriptEnginePointer ScriptContextQtWrapper::engine() const { - return _engine->sharedFromThis(); + return _engine->shared_from_this(); } ScriptFunctionContextPointer ScriptContextQtWrapper::functionContext() const { - return ScriptFunctionContextPointer(new ScriptFunctionContextQtWrapper(_context)); + return std::make_shared(_context); } ScriptContextPointer ScriptContextQtWrapper::parentContext() const { QScriptContext* result = _context->parentContext(); - return result ? ScriptContextPointer(new ScriptContextQtWrapper(_engine, result)) : ScriptContextPointer(); + return result ? std::make_shared(_engine, result) : ScriptContextPointer(); } ScriptValue ScriptContextQtWrapper::thisObject() const { diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index c4a00188f12..ae76b2f627d 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -777,7 +777,7 @@ ScriptValue ScriptEngineQtScript::newObject() { ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, const QString& fileName) { QScriptProgram result(sourceCode, fileName); - return ScriptProgramPointer(new ScriptProgramQtWrapper(this, result)); + return std::make_shared(this, result); } ScriptValue ScriptEngineQtScript::newQObject(QObject* object, @@ -857,7 +857,7 @@ ScriptContext* ScriptEngineQtScript::currentContext() const { return nullptr; } if (!_currContext || _currContext->toQtValue() != localCtx) { - _currContext = ScriptContextQtPointer(new ScriptContextQtWrapper(const_cast(this), localCtx)); + _currContext = std::make_shared(const_cast(this), localCtx); } return _currContext.get(); } diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index d073ad97497..3d99f0a39c0 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -16,12 +16,12 @@ #ifndef hifi_ScriptEngineQtScript_h #define hifi_ScriptEngineQtScript_h +#include + #include -#include #include #include #include -#include #include #include @@ -35,15 +35,15 @@ class ScriptContextQtWrapper; class ScriptContextQtAgent; class ScriptEngineQtScript; class ScriptManager; -using ScriptEngineQtScriptPointer = QSharedPointer; -using ScriptContextQtPointer = QSharedPointer; +using ScriptEngineQtScriptPointer = std::shared_ptr; +using ScriptContextQtPointer = std::shared_ptr; Q_DECLARE_METATYPE(ScriptEngineQtScriptPointer); /// [QtScript] Implements ScriptEngine for QtScript and translates calls for QScriptEngine class ScriptEngineQtScript final : public QScriptEngine, public ScriptEngine, - public QEnableSharedFromThis { + public std::enable_shared_from_this { Q_OBJECT public: // construction diff --git a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp index 11dba1417e5..3a5b2ae68e6 100644 --- a/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptProgramQtWrapper.cpp @@ -26,7 +26,7 @@ ScriptProgramQtWrapper* ScriptProgramQtWrapper::unwrap(ScriptProgramPointer val) ScriptSyntaxCheckResultPointer ScriptProgramQtWrapper::checkSyntax() const { QScriptSyntaxCheckResult result = _engine->checkSyntax(_value.sourceCode()); - return ScriptSyntaxCheckResultPointer(new ScriptSyntaxCheckResultQtWrapper(std::move(result))); + return std::make_shared(std::move(result)); } QString ScriptProgramQtWrapper::fileName() const { diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp index 768ec412466..4eb32476ea0 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp @@ -84,11 +84,11 @@ ScriptEnginePointer ScriptValueQtWrapper::engine() const { if (!_engine) { return ScriptEnginePointer(); } - return _engine->sharedFromThis(); + return _engine->shared_from_this(); } ScriptValueIteratorPointer ScriptValueQtWrapper::newIterator() const { - return ScriptValueIteratorPointer(new ScriptValueIteratorQtWrapper(_engine, _value)); + return std::make_shared(_engine, _value); } ScriptValue ScriptValueQtWrapper::property(const QString& name, const ScriptValue::ResolveFlags& mode) const { From c036c04b6a34e387b313d436a976747f6a8e58ff Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 14 Nov 2021 20:45:20 -0800 Subject: [PATCH 23/34] changes from code review suggestions --- interface/src/ui/JSConsole.cpp | 2 +- interface/src/ui/TestingDialog.cpp | 8 +++---- interface/src/ui/TestingDialog.h | 2 +- .../entities/src/EntityScriptingInterface.cpp | 18 +++++++-------- .../entities/src/EntityScriptingInterface.h | 4 ++-- libraries/script-engine/src/ScriptEngine.h | 2 +- libraries/script-engine/src/Scriptable.cpp | 6 ++--- libraries/script-engine/src/Scriptable.h | 12 ++++------ .../src/qtscript/ScriptContextQtAgent.h | 2 +- .../src/qtscript/ScriptEngineQtScript.cpp | 22 +++++++++---------- .../src/qtscript/ScriptEngineQtScript.h | 2 +- 11 files changed, 38 insertions(+), 42 deletions(-) diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 77b8af22e2c..89b20918d77 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -318,7 +318,7 @@ void JSConsole::setScriptManager(const ScriptManagerPointer& scriptManager) { if (_scriptManager == scriptManager && scriptManager != nullptr) { return; } - if (scriptManager != nullptr) { + if (_scriptManager != nullptr) { disconnect(_scriptManager.get(), nullptr, this, nullptr); _scriptManager.reset(); } diff --git a/interface/src/ui/TestingDialog.cpp b/interface/src/ui/TestingDialog.cpp index 49653c032f7..efaf49fc1a3 100644 --- a/interface/src/ui/TestingDialog.cpp +++ b/interface/src/ui/TestingDialog.cpp @@ -24,12 +24,12 @@ TestingDialog::TestingDialog(QWidget* parent) : _console->setFixedHeight(TESTING_CONSOLE_HEIGHT); - _manager = DependencyManager::get()->loadScript(qApp->applicationDirPath() + testRunnerRelativePath); - _console->setScriptManager(_manager); - connect(_manager.get(), &ScriptManager::finished, this, &TestingDialog::onTestingFinished); + _scriptManager = DependencyManager::get()->loadScript(qApp->applicationDirPath() + testRunnerRelativePath); + _console->setScriptManager(_scriptManager); + connect(_scriptManager.get(), &ScriptManager::finished, this, &TestingDialog::onTestingFinished); } void TestingDialog::onTestingFinished(const QString& scriptPath) { - _manager.reset(); + _scriptManager.reset(); _console->setScriptManager(); } diff --git a/interface/src/ui/TestingDialog.h b/interface/src/ui/TestingDialog.h index 21977373253..7707213b037 100644 --- a/interface/src/ui/TestingDialog.h +++ b/interface/src/ui/TestingDialog.h @@ -33,7 +33,7 @@ class TestingDialog : public QDialog { private: std::unique_ptr _console; - ScriptManagerPointer _manager; + ScriptManagerPointer _scriptManager; }; #endif diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8ed610dc691..6efb4f46714 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -53,7 +53,7 @@ void staticEntityScriptInitializer(ScriptManager* manager) { auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->init(); - auto ifacePtr = entityScriptingInterface.data(); // using this when we don't want to leak a reference + auto interfacePtr = entityScriptingInterface.data(); // using this when we don't want to leak a reference registerMetaTypes(scriptEngine); @@ -71,7 +71,7 @@ void staticEntityScriptInitializer(ScriptManager* manager) { // so... yay lambdas everywhere to get the sender manager->connect( manager, &ScriptManager::attachDefaultEventHandlers, entityScriptingInterface.data(), - [ifacePtr, manager] { ifacePtr->attachDefaultEventHandlers(manager); }, + [interfacePtr, manager] { interfacePtr->attachDefaultEventHandlers(manager); }, Qt::DirectConnection); manager->connect(manager, &ScriptManager::releaseEntityPacketSenderMessages, entityScriptingInterface.data(), &EntityScriptingInterface::releaseEntityPacketSenderMessages, Qt::DirectConnection); @@ -99,7 +99,7 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership void EntityScriptingInterface::releaseEntityPacketSenderMessages(bool wait) { EntityEditPacketSender* entityPacketSender = getEntityPacketSender(); - if (entityPacketSender->serversExist()) { + if (entityPacketSender && entityPacketSender->serversExist()) { // release the queue of edit entity messages. entityPacketSender->releaseQueuedMessages(); @@ -1513,17 +1513,17 @@ bool EntityPropertyMetadataRequest::script(EntityItemID entityID, const ScriptVa using LocalScriptStatusRequest = QFutureWatcher; LocalScriptStatusRequest* request = new LocalScriptStatusRequest; - QObject::connect(request, &LocalScriptStatusRequest::finished, _manager, [=]() mutable { + QObject::connect(request, &LocalScriptStatusRequest::finished, _scriptManager, [=]() mutable { auto details = request->result().toMap(); ScriptValue err, result; if (details.contains("isError")) { if (!details.contains("message")) { details["message"] = details["errorInfo"]; } - err = _manager->engine()->makeError(_manager->engine()->toScriptValue(details)); + err = _scriptManager->engine()->makeError(_scriptManager->engine()->toScriptValue(details)); } else { details["success"] = true; - result = _manager->engine()->toScriptValue(details); + result = _scriptManager->engine()->toScriptValue(details); } callScopedHandlerObject(handler, err, result); request->deleteLater(); @@ -1546,9 +1546,9 @@ bool EntityPropertyMetadataRequest::script(EntityItemID entityID, const ScriptVa bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, const ScriptValue& handler) { auto client = DependencyManager::get(); auto request = client->createScriptStatusRequest(entityID); - QPointer manager = _manager; - QObject::connect(request, &GetScriptStatusRequest::finished, _manager, [=](GetScriptStatusRequest* request) mutable { - auto manager = _manager; + QPointer manager = _scriptManager; + QObject::connect(request, &GetScriptStatusRequest::finished, _scriptManager, [=](GetScriptStatusRequest* request) mutable { + auto manager = _scriptManager; if (!manager) { qCDebug(entities) << __FUNCTION__ << " -- engine destroyed while inflight" << entityID; return; diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 774228cfdc7..b878837eb22 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -55,11 +55,11 @@ extern const QString NOT_GRABBABLE_USER_DATA; // problems with their own Entity scripts. class EntityPropertyMetadataRequest { public: - EntityPropertyMetadataRequest(ScriptManager* manager) : _manager(manager == nullptr ? nullptr : manager){}; + EntityPropertyMetadataRequest(ScriptManager* manager) : _scriptManager(manager){}; bool script(EntityItemID entityID, const ScriptValue& handler); bool serverScripts(EntityItemID entityID, const ScriptValue& handler); private: - QPointer _manager; + QPointer _scriptManager; }; /*@jsdoc diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index c69a0af8c31..d611e375599 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -61,7 +61,7 @@ class ScriptEngine { //ExcludeChildObjects = 0x0001, // The script object will not expose child objects as properties. ExcludeSuperClassMethods = 0x0002, // The script object will not expose signals and slots inherited from the superclass. ExcludeSuperClassProperties = 0x0004, // The script object will not expose properties inherited from the superclass. - ExcludeSuperClassContents = 0x0006, // Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties + ExcludeSuperClassContents = ExcludeSuperClassMethods | ExcludeSuperClassProperties, //ExcludeDeleteLater = 0x0010, // The script object will not expose the QObject::deleteLater() slot. ExcludeSlots = 0x0020, // The script object will not expose the QObject's slots. AutoCreateDynamicProperties = 0x0100, // Properties that don't already exist in the QObject will be created as dynamic properties of that object, rather than as properties of the script object. diff --git a/libraries/script-engine/src/Scriptable.cpp b/libraries/script-engine/src/Scriptable.cpp index 1ba432b061f..07860ce6df1 100644 --- a/libraries/script-engine/src/Scriptable.cpp +++ b/libraries/script-engine/src/Scriptable.cpp @@ -11,12 +11,12 @@ #include "Scriptable.h" -static thread_local ScriptContext* ScriptContextStore; +static thread_local ScriptContext* scriptContextStore; ScriptContext* Scriptable::context() { - return ScriptContextStore; + return scriptContextStore; } void Scriptable::setContext(ScriptContext* context) { - ScriptContextStore = context; + scriptContextStore = context; } diff --git a/libraries/script-engine/src/Scriptable.h b/libraries/script-engine/src/Scriptable.h index 45669a111cc..d2ca04ac69e 100644 --- a/libraries/script-engine/src/Scriptable.h +++ b/libraries/script-engine/src/Scriptable.h @@ -37,26 +37,22 @@ class Scriptable { ScriptEnginePointer Scriptable::engine() { ScriptContext* scriptContext = context(); - if (!scriptContext) return nullptr; - return scriptContext->engine(); + return scriptContext ? scriptContext->engine() : nullptr; } ScriptValue Scriptable::thisObject() { ScriptContext* scriptContext = context(); - if (!scriptContext) return ScriptValue(); - return scriptContext->thisObject(); + return scriptContext ? scriptContext->thisObject() : ScriptValue(); } int Scriptable::argumentCount() { ScriptContext* scriptContext = context(); - if (!scriptContext) return 0; - return scriptContext->argumentCount(); + return scriptContext ? scriptContext->argumentCount() : 0; } ScriptValue Scriptable::argument(int index) { ScriptContext* scriptContext = context(); - if (!scriptContext) return ScriptValue(); - return scriptContext->argument(index); + return scriptContext ? scriptContext->argument(index) : ScriptValue(); } #endif // hifi_Scriptable_h diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h index f23d82dc2bc..0869e5a50ff 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h +++ b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h @@ -38,7 +38,7 @@ class ScriptContextQtAgent final : public QScriptEngineAgent { virtual void functionExit(qint64 scriptId, const QScriptValue& returnValue) override; private: // storage - bool _contextActive = false; + bool _contextActive{ false }; QList _contextStack; ScriptContextQtPointer _currContext; ScriptEngineQtScript* _engine; diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index ae76b2f627d..c2c25f9bb8b 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -229,11 +229,11 @@ bool ScriptEngineQtScript::raiseException(const QScriptValue& exception) { // we have an active context / JS stack frame so throw the exception per usual QScriptEngine::currentContext()->throwValue(makeError(exception)); return true; - } else if(_manager) { + } else if (_scriptManager) { // we are within a pure C++ stack frame (ie: being called directly by other C++ code) // in this case no context information is available so just emit the exception for reporting QScriptValue thrown = makeError(exception); - emit _manager->unhandledException(ScriptValue(new ScriptValueQtWrapper(this, std::move(thrown)))); + emit _scriptManager->unhandledException(ScriptValue(new ScriptValueQtWrapper(this, std::move(thrown)))); } return false; } @@ -242,8 +242,8 @@ bool ScriptEngineQtScript::maybeEmitUncaughtException(const QString& debugHint) if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return false; } - if (!isEvaluating() && hasUncaughtException() && _manager) { - emit _manager->unhandledException(cloneUncaughtException(debugHint)); + if (!isEvaluating() && hasUncaughtException() && _scriptManager) { + emit _scriptManager->unhandledException(cloneUncaughtException(debugHint)); clearExceptions(); return true; } @@ -322,21 +322,21 @@ static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValue& de ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : QScriptEngine(), - _manager(scriptManager), + _scriptManager(scriptManager), _arrayBufferClass(new ArrayBufferClass(this)) { qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue); - if (_manager) { + if (_scriptManager) { connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { if (hasUncaughtException()) { // the engine's uncaughtException() seems to produce much better stack traces here - emit _manager->unhandledException(cloneUncaughtException("signalHandlerException")); + emit _scriptManager->unhandledException(cloneUncaughtException("signalHandlerException")); clearExceptions(); } else { // ... but may not always be available -- so if needed we fallback to the passed exception QScriptValue thrown = makeError(exception); - emit _manager->unhandledException(ScriptValue(new ScriptValueQtWrapper(this, std::move(thrown)))); + emit _scriptManager->unhandledException(ScriptValue(new ScriptValueQtWrapper(this, std::move(thrown)))); } }, Qt::DirectConnection); moveToThread(scriptManager->thread()); @@ -649,7 +649,7 @@ ScriptValue ScriptEngineQtScript::evaluateInClosure(const ScriptValue& _closure, } ScriptValue ScriptEngineQtScript::evaluate(const QString& sourceCode, const QString& fileName) { - if (_manager && _manager->isStopped()) { + if (_scriptManager && _scriptManager->isStopped()) { return undefinedValue(); // bail early } @@ -692,7 +692,7 @@ ScriptValue ScriptEngineQtScript::evaluate(const QString& sourceCode, const QStr } Q_INVOKABLE ScriptValue ScriptEngineQtScript::evaluate(const ScriptProgramPointer& program) { - if (_manager && _manager->isStopped()) { + if (_scriptManager && _scriptManager->isStopped()) { return undefinedValue(); // bail early } @@ -751,7 +751,7 @@ ScriptValue ScriptEngineQtScript::globalObject() const { } ScriptManager* ScriptEngineQtScript::manager() const { - return _manager; + return _scriptManager; } ScriptValue ScriptEngineQtScript::newArray(uint length) { diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 3d99f0a39c0..9d1e54d1b35 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -163,7 +163,7 @@ class ScriptEngineQtScript final : public QScriptEngine, const QScriptEngine::ValueOwnership& ownership = QScriptEngine::AutoOwnership); protected: - QPointer _manager; + QPointer _scriptManager; int _nextCustomType = 0; ScriptValue _nullValue; From 9eb325f9358bf9906ecfd7763754cd4517489c80 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Tue, 14 Dec 2021 00:30:08 -0800 Subject: [PATCH 24/34] first pass creating Qt <-> QtScript interface --- interface/src/LODManager.cpp | 3 +- interface/src/LODManager.h | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +- interface/src/avatar/MyAvatar.h | 4 +- .../src/raypick/PickScriptingInterface.cpp | 3 +- .../AccountServicesScriptingInterface.cpp | 3 +- .../AccountServicesScriptingInterface.h | 2 +- interface/src/ui/InteractiveWindow.cpp | 3 +- interface/src/ui/InteractiveWindow.h | 2 +- interface/src/ui/overlays/Overlays.cpp | 3 +- interface/src/ui/overlays/Overlays.h | 2 +- libraries/audio/src/AudioInjectorOptions.cpp | 5 +- libraries/audio/src/AudioInjectorOptions.h | 2 +- libraries/audio/src/ScriptAudioInjector.cpp | 3 +- libraries/audio/src/ScriptAudioInjector.h | 2 +- libraries/audio/src/Sound.cpp | 3 +- libraries/audio/src/Sound.h | 2 +- libraries/avatars/src/AvatarData.cpp | 6 +- libraries/avatars/src/AvatarData.h | 4 +- libraries/avatars/src/ScriptAvatarData.cpp | 3 +- .../controllers/src/controllers/Pose.cpp | 3 +- libraries/controllers/src/controllers/Pose.h | 2 +- .../src/controllers/ScriptingInterface.cpp | 3 +- .../src/controllers/UserInputMapper.cpp | 20 +- .../entities/src/EntityItemProperties.cpp | 16 +- libraries/entities/src/EntityItemProperties.h | 10 +- .../entities/src/EntityScriptingInterface.cpp | 3 +- .../entities/src/EntityScriptingInterface.h | 2 +- .../GraphicsScriptingInterface.cpp | 22 +- libraries/script-engine/src/KeyEvent.cpp | 3 +- libraries/script-engine/src/KeyEvent.h | 2 +- libraries/script-engine/src/MIDIEvent.cpp | 3 +- libraries/script-engine/src/MIDIEvent.h | 2 +- .../script-engine/src/MenuItemProperties.cpp | 3 +- .../script-engine/src/MenuItemProperties.h | 2 +- libraries/script-engine/src/MouseEvent.cpp | 3 +- libraries/script-engine/src/MouseEvent.h | 2 +- libraries/script-engine/src/PointerEvent.cpp | 3 +- libraries/script-engine/src/PointerEvent.h | 2 +- libraries/script-engine/src/ScriptContext.cpp | 23 + libraries/script-engine/src/ScriptContext.h | 9 + libraries/script-engine/src/ScriptEngine.h | 6 +- .../script-engine/src/ScriptEngineCast.h | 22 +- libraries/script-engine/src/ScriptManager.cpp | 11 +- libraries/script-engine/src/ScriptManager.h | 9 + .../script-engine/src/ScriptValueUtils.cpp | 91 ++- .../script-engine/src/ScriptValueUtils.h | 58 +- libraries/script-engine/src/SpatialEvent.cpp | 3 +- libraries/script-engine/src/SpatialEvent.h | 2 +- libraries/script-engine/src/TouchEvent.cpp | 3 +- libraries/script-engine/src/TouchEvent.h | 2 +- .../script-engine/src/WebSocketClass.cpp | 9 +- libraries/script-engine/src/WebSocketClass.h | 6 +- libraries/script-engine/src/WheelEvent.cpp | 3 +- libraries/script-engine/src/WheelEvent.h | 2 +- .../src/qtscript/ArrayBufferClass.cpp | 3 +- .../src/qtscript/ScriptEngineQtScript.cpp | 149 +---- .../src/qtscript/ScriptEngineQtScript.h | 21 +- .../qtscript/ScriptEngineQtScript_cast.cpp | 538 +++++++++++++++ .../src/qtscript/ScriptObjectQtProxy.cpp | 622 ++++++++++++++++++ .../src/qtscript/ScriptObjectQtProxy.h | 205 ++++++ .../src/qtscript/ScriptValueQtWrapper.cpp | 32 +- libraries/ui/src/ui/QmlWrapper.h | 3 +- 63 files changed, 1707 insertions(+), 294 deletions(-) create mode 100644 libraries/script-engine/src/ScriptContext.cpp create mode 100644 libraries/script-engine/src/qtscript/ScriptEngineQtScript_cast.cpp create mode 100644 libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp create mode 100644 libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 9a80c5478b7..3acd4f47819 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -430,9 +430,10 @@ ScriptValue worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDet return engine->newValue(worldDetailQuality); } -void worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality) { +bool worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality) { worldDetailQuality = static_cast(std::min(std::max(object.toInt32(), (int)WORLD_DETAIL_LOW), (int)WORLD_DETAIL_HIGH)); + return true; } void LODManager::setLODQualityLevel(float quality) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 1ab64b2dc16..afebe9d7747 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -383,6 +383,6 @@ class LODManager : public QObject, public Dependency { }; ScriptValue worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality); -void worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality); +bool worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality); #endif // hifi_LODManager_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 13028822b71..3fdcc6f1d34 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -5705,16 +5705,18 @@ ScriptValue audioListenModeToScriptValue(ScriptEngine* engine, const AudioListen return engine->newValue(audioListenerMode); } -void audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode) { +bool audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode) { audioListenerMode = static_cast(object.toUInt16()); + return true; } ScriptValue driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys) { return engine->newValue(driveKeys); } -void driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys) { +bool driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys) { driveKeys = static_cast(object.toUInt16()); + return true; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 425bcca3588..2811768a154 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -3118,10 +3118,10 @@ private slots: }; ScriptValue audioListenModeToScriptValue(ScriptEngine* engine, const AudioListenerMode& audioListenerMode); -void audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode); +bool audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode); ScriptValue driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys); -void driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys); +bool driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys); bool isWearableEntity(const EntityItemPointer& entity); diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index eba2dec19e8..b5ef887f628 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -451,8 +451,9 @@ ScriptValue pickTypesToScriptValue(ScriptEngine* engine, const PickQuery::PickTy return engine->newValue(pickType); } -void pickTypesFromScriptValue(const ScriptValue& object, PickQuery::PickType& pickType) { +bool pickTypesFromScriptValue(const ScriptValue& object, PickQuery::PickType& pickType) { pickType = static_cast(object.toUInt16()); + return true; } void PickScriptingInterface::registerMetaTypes(ScriptEngine* engine) { diff --git a/interface/src/scripting/AccountServicesScriptingInterface.cpp b/interface/src/scripting/AccountServicesScriptingInterface.cpp index ccd4ca83393..1ae023229c9 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.cpp +++ b/interface/src/scripting/AccountServicesScriptingInterface.cpp @@ -131,7 +131,7 @@ ScriptValue DownloadInfoResultToScriptValue(ScriptEngine* engine, const Download return object; } -void DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result) { +bool DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result) { QList downloading = object.property("downloading").toVariant().toList(); result.downloading.clear(); for (int i = 0; i < downloading.count(); i += 1) { @@ -139,6 +139,7 @@ void DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoRe } result.pending = object.property("pending").toVariant().toFloat(); + return true; } DownloadInfoResult AccountServicesScriptingInterface::getDownloadInfo() { diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index b9d453395d5..56e91a30804 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -32,7 +32,7 @@ class DownloadInfoResult { Q_DECLARE_METATYPE(DownloadInfoResult) ScriptValue DownloadInfoResultToScriptValue(ScriptEngine* engine, const DownloadInfoResult& result); -void DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result); +bool DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result); class AccountServicesScriptingInterface : public QObject { Q_OBJECT diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index f74c61dea32..cda66c5cf27 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -101,10 +101,11 @@ ScriptValue interactiveWindowPointerToScriptValue(ScriptEngine* engine, const In return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out) { +bool interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out) { if (const auto interactiveWindow = qobject_cast(object.toQObject())) { out = interactiveWindow; } + return true; } void InteractiveWindow::forwardKeyPressEvent(int key, int modifiers) { diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h index f11140b3c33..9cce6944cbd 100644 --- a/interface/src/ui/InteractiveWindow.h +++ b/interface/src/ui/InteractiveWindow.h @@ -411,7 +411,7 @@ protected slots: typedef InteractiveWindow* InteractiveWindowPointer; ScriptValue interactiveWindowPointerToScriptValue(ScriptEngine* engine, const InteractiveWindowPointer& in); -void interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out); +bool interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out); void registerInteractiveWindowMetaType(ScriptEngine* engine); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 72e2748daf4..98fd33939b8 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -1126,7 +1126,7 @@ ScriptValue RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, co return obj; } -void RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value) { +bool RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value) { value.intersects = object.property("intersects").toVariant().toBool(); ScriptValue overlayIDValue = object.property("overlayID"); quuidFromScriptValue(overlayIDValue, value.overlayID); @@ -1142,6 +1142,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, Ra vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } value.extraInfo = object.property("extraInfo").toVariant().toMap(); + return true; } bool Overlays::isLoaded(const QUuid& id) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 167a0e1d7d6..d13e2f821cd 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -54,7 +54,7 @@ class RayToOverlayIntersectionResult { }; Q_DECLARE_METATYPE(RayToOverlayIntersectionResult); ScriptValue RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value); -void RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value); +bool RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value); class ParabolaToOverlayIntersectionResult { public: diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 94597e4757f..804d935a46d 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -66,10 +66,10 @@ ScriptValue injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInject * @property {boolean} ignorePenumbra=false -

Deprecated: This property is deprecated and will be * removed.

*/ -void injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions) { +bool injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions) { if (!object.isObject()) { qWarning() << "Audio injector options is not an object."; - return; + return false; } if (injectorOptions.positionSet == false) { @@ -126,4 +126,5 @@ void injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOpti qCWarning(audio) << "Unknown audio injector option:" << it->name(); } } + return true; } diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index 0dd3ab1cb14..fda05f01177 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -37,6 +37,6 @@ class AudioInjectorOptions { Q_DECLARE_METATYPE(AudioInjectorOptions); ScriptValue injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInjectorOptions& injectorOptions); -void injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions); +bool injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions); #endif // hifi_AudioInjectorOptions_h diff --git a/libraries/audio/src/ScriptAudioInjector.cpp b/libraries/audio/src/ScriptAudioInjector.cpp index 09f24c72077..28af8b849aa 100644 --- a/libraries/audio/src/ScriptAudioInjector.cpp +++ b/libraries/audio/src/ScriptAudioInjector.cpp @@ -32,8 +32,9 @@ ScriptValue injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* con return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out) { +bool injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out) { out = qobject_cast(object.toQObject()); + return true; } ScriptAudioInjector::ScriptAudioInjector(const AudioInjectorPointer& injector) : diff --git a/libraries/audio/src/ScriptAudioInjector.h b/libraries/audio/src/ScriptAudioInjector.h index 7a55341756c..18d0ba72a48 100644 --- a/libraries/audio/src/ScriptAudioInjector.h +++ b/libraries/audio/src/ScriptAudioInjector.h @@ -152,7 +152,7 @@ public slots: Q_DECLARE_METATYPE(ScriptAudioInjector*) ScriptValue injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in); -void injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out); +bool injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out); #endif // hifi_ScriptAudioInjector_h diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index a880da037cf..e0f70cc121a 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -428,10 +428,11 @@ ScriptValue soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSo return engine->newQObject(new SoundScriptingInterface(in), ScriptEngine::ScriptOwnership); } -void soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out) { +bool soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out) { if (auto soundInterface = qobject_cast(object.toQObject())) { out = soundInterface->getSound(); } + return true; } SoundScriptingInterface::SoundScriptingInterface(const SharedSoundPointer& sound) : _sound(sound) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index f98822249f2..f38d2991ce1 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -172,6 +172,6 @@ class SoundScriptingInterface : public QObject { Q_DECLARE_METATYPE(SharedSoundPointer) ScriptValue soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in); -void soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out); +bool soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out); #endif // hifi_Sound_h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b7683e34aba..373d1e30af3 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -3170,7 +3170,7 @@ ScriptValue RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, con return obj; } -void RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& value) { +bool RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& value) { value.intersects = object.property("intersects").toVariant().toBool(); ScriptValue avatarIDValue = object.property("avatarID"); quuidFromScriptValue(avatarIDValue, value.avatarID); @@ -3187,6 +3187,7 @@ void RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, Ray } value.jointIndex = object.property("jointIndex").toInt32(); value.extraInfo = object.property("extraInfo").toVariant().toMap(); + return true; } // these coefficients can be changed via JS for experimental tuning @@ -3218,7 +3219,7 @@ ScriptValue AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntit return obj; } -void AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value) { +bool AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value) { ScriptValueIteratorPointer itr(object.newIterator()); while (itr->hasNext()) { itr->next(); @@ -3231,6 +3232,7 @@ void AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value[EntityID] = binaryEntityProperties; } + return true; } const float AvatarData::DEFAULT_BUBBLE_SCALE = 2.4f; // magic number determined empirically diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 9f0b93fabb7..7231e882dea 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1971,7 +1971,7 @@ class RayToAvatarIntersectionResult { }; Q_DECLARE_METATYPE(RayToAvatarIntersectionResult) ScriptValue RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, const RayToAvatarIntersectionResult& results); -void RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& results); +bool RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& results); // No JSDoc because it's not provided as a type to the script engine. class ParabolaToAvatarIntersectionResult { @@ -1989,7 +1989,7 @@ class ParabolaToAvatarIntersectionResult { Q_DECLARE_METATYPE(AvatarEntityMap) ScriptValue AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntityMap& value); -void AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value); +bool AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value); // faux joint indexes (-1 means invalid) const int NO_JOINT_INDEX = 65535; // -1 diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index 9f23fee84a9..5335f8ab5b3 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -18,10 +18,11 @@ ScriptValue avatarDataToScriptValue(ScriptEngine* engine, ScriptAvatarData* cons return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void avatarDataFromScriptValue(const ScriptValue& object, ScriptAvatarData*& out) { +bool avatarDataFromScriptValue(const ScriptValue& object, ScriptAvatarData*& out) { // This is not implemented because there are no slots/properties that take an AvatarSharedPointer from a script assert(false); out = nullptr; + return false; } STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index bfb6f6afc42..1fad0b9c42d 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -50,7 +50,7 @@ namespace controller { return obj; } - void Pose::fromScriptValue(const ScriptValue& object, Pose& pose) { + bool Pose::fromScriptValue(const ScriptValue& object, Pose& pose) { auto translation = object.property("translation"); auto rotation = object.property("rotation"); auto velocity = object.property("velocity"); @@ -67,6 +67,7 @@ namespace controller { } else { pose.valid = false; } + return true; } Pose Pose::transform(const glm::mat4& mat) const { diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h index 7a71c7c5bbc..a1bcbffd2d0 100644 --- a/libraries/controllers/src/controllers/Pose.h +++ b/libraries/controllers/src/controllers/Pose.h @@ -45,7 +45,7 @@ namespace controller { Pose postTransform(const glm::mat4& mat) const; static ScriptValue toScriptValue(ScriptEngine* engine, const Pose& event); - static void fromScriptValue(const ScriptValue& object, Pose& event); + static bool fromScriptValue(const ScriptValue& object, Pose& event); }; } diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index b6e57a0c4e1..6f84255b4ba 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -37,8 +37,9 @@ ScriptValue inputControllerToScriptValue(ScriptEngine* engine, controller::Input return engine->newQObject(in, ScriptEngine::QtOwnership); } -void inputControllerFromScriptValue(const ScriptValue& object, controller::InputController*& out) { +bool inputControllerFromScriptValue(const ScriptValue& object, controller::InputController*& out) { out = qobject_cast(object.toQObject()); + return true; } STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 8e3b7682391..d1fca933f54 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -393,13 +393,13 @@ int poseMetaTypeId = qRegisterMetaType("Pose"); int handMetaTypeId = qRegisterMetaType(); ScriptValue inputToScriptValue(ScriptEngine* engine, const Input& input); -void inputFromScriptValue(const ScriptValue& object, Input& input); +bool inputFromScriptValue(const ScriptValue& object, Input& input); ScriptValue actionToScriptValue(ScriptEngine* engine, const Action& action); -void actionFromScriptValue(const ScriptValue& object, Action& action); +bool actionFromScriptValue(const ScriptValue& object, Action& action); ScriptValue inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair); -void inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair); +bool inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair); ScriptValue handToScriptValue(ScriptEngine* engine, const controller::Hand& hand); -void handFromScriptValue(const ScriptValue& object, controller::Hand& hand); +bool handFromScriptValue(const ScriptValue& object, controller::Hand& hand); ScriptValue inputToScriptValue(ScriptEngine* engine, const Input& input) { ScriptValue obj = engine->newObject(); @@ -410,8 +410,9 @@ ScriptValue inputToScriptValue(ScriptEngine* engine, const Input& input) { return obj; } -void inputFromScriptValue(const ScriptValue& object, Input& input) { +bool inputFromScriptValue(const ScriptValue& object, Input& input) { input.id = object.property("id").toInt32(); + return true; } ScriptValue actionToScriptValue(ScriptEngine* engine, const Action& action) { @@ -422,8 +423,9 @@ ScriptValue actionToScriptValue(ScriptEngine* engine, const Action& action) { return obj; } -void actionFromScriptValue(const ScriptValue& object, Action& action) { +bool actionFromScriptValue(const ScriptValue& object, Action& action) { action = Action(object.property("action").toVariant().toInt()); + return true; } ScriptValue inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair) { @@ -433,17 +435,19 @@ ScriptValue inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& return obj; } -void inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair) { +bool inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair) { inputFromScriptValue(object.property("input"), inputPair.first); inputPair.second = QString(object.property("inputName").toVariant().toString()); + return true; } ScriptValue handToScriptValue(ScriptEngine* engine, const controller::Hand& hand) { return engine->newValue((int)hand); } -void handFromScriptValue(const ScriptValue& object, controller::Hand& hand) { +bool handFromScriptValue(const ScriptValue& object, controller::Hand& hand) { hand = Hand(object.toVariant().toInt()); + return true; } void UserInputMapper::registerControllerTypes(ScriptEngine* engine) { diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 874abd776b7..fcafd75ea9e 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2584,20 +2584,22 @@ ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, co return properties.copyToScriptValue(engine, true); } -void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue &object, EntityItemProperties& properties) { +bool EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue &object, EntityItemProperties& properties) { properties.copyFromScriptValue(object, false); + return true; } -void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue &object, EntityItemProperties& properties) { +bool EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue &object, EntityItemProperties& properties) { properties.copyFromScriptValue(object, true); + return true; } ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { return EntityItemProperties::entityPropertyFlagsToScriptValue(engine, flags); } -void EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { - EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags); +bool EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { + return EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags); } @@ -2606,7 +2608,7 @@ ScriptValue EntityItemProperties::entityPropertyFlagsToScriptValue(ScriptEngine* return result; } -void EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { +bool EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { if (object.isString()) { EntityPropertyInfo propertyInfo; if (getPropertyInfo(object.toString(), propertyInfo)) { @@ -2623,6 +2625,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue& } } } + return true; } static QHash _propertyInfos; @@ -3023,10 +3026,11 @@ ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPr return obj; } -void EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo) { +bool EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo) { propertyInfo.propertyEnum = (EntityPropertyList)object.property("propertyEnum").toVariant().toUInt(); propertyInfo.minimum = object.property("minimum").toVariant(); propertyInfo.maximum = object.property("maximum").toVariant(); + return true; } // TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index c8016461d73..678bd9680a5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -141,7 +141,7 @@ class EntityItemProperties { void copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString); static ScriptValue entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); - static void entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); + static bool entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); static bool getPropertyInfo(const QString& propertyName, EntityPropertyInfo& propertyInfo); @@ -543,16 +543,16 @@ class EntityItemProperties { Q_DECLARE_METATYPE(EntityItemProperties); ScriptValue EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue& object, EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue& object, EntityItemProperties& properties); +bool EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue& object, EntityItemProperties& properties); +bool EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue& object, EntityItemProperties& properties); Q_DECLARE_METATYPE(EntityPropertyFlags); ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); -void EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); +bool EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); Q_DECLARE_METATYPE(EntityPropertyInfo); ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo); -void EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo); +bool EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo); // define these inline here so the macros work inline void EntityItemProperties::setPosition(const glm::vec3& value) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6efb4f46714..f93ad4ef97b 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1690,7 +1690,7 @@ ScriptValue RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, con return obj; } -void RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& value) { +bool RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& value) { value.intersects = object.property("intersects").toVariant().toBool(); value.accurate = object.property("accurate").toVariant().toBool(); ScriptValue entityIDValue = object.property("entityID"); @@ -1707,6 +1707,7 @@ void RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, Ray vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } value.extraInfo = object.property("extraInfo").toVariant().toMap(); + return true; } bool EntityScriptingInterface::polyVoxWorker(QUuid entityID, std::function actor) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 730feba981e..46208966f1a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -92,7 +92,7 @@ class RayToEntityIntersectionResult { }; Q_DECLARE_METATYPE(RayToEntityIntersectionResult) ScriptValue RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, const RayToEntityIntersectionResult& results); -void RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& results); +bool RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& results); class ParabolaToEntityIntersectionResult { public: diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index eedeae2a3d7..819b6c5b4da 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -325,14 +325,14 @@ namespace scriptable { } return engine->newQObject(object, ScriptEngine::QtOwnership, ScriptEngine::AutoCreateDynamicProperties); }, - [](const ScriptValue& value, QPointer& out) { + [](const ScriptValue& value, QPointer& out) -> bool { auto obj = value.toQObject(); #ifdef SCRIPTABLE_MESH_DEBUG qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString(); #endif if (auto tmp = qobject_cast(obj)) { out = QPointer(tmp); - return; + return true; } #if 0 if (auto tmp = static_cast(obj)) { @@ -340,10 +340,11 @@ namespace scriptable { qCInfo(graphics_scripting) << "qpointer_qobject_cast -- via static_cast" << obj << tmp << value.toString(); #endif out = QPointer(tmp); - return; + return true; } #endif out = nullptr; + return false; } ); } @@ -352,8 +353,9 @@ namespace scriptable { return scriptValueFromSequence(engine, vector); } - void qVectorScriptableMaterialLayerFromScriptValue(const ScriptValue& array, QVector& result) { + bool qVectorScriptableMaterialLayerFromScriptValue(const ScriptValue& array, QVector& result) { scriptValueToSequence(array, result); + return true; } /*@jsdoc @@ -625,8 +627,9 @@ namespace scriptable { return obj; } - void scriptableMaterialFromScriptValue(const ScriptValue &object, scriptable::ScriptableMaterial& material) { + bool scriptableMaterialFromScriptValue(const ScriptValue& object, scriptable::ScriptableMaterial& material) { // No need to convert from ScriptValue to ScriptableMaterial + return false; } ScriptValue scriptableMaterialLayerToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) { @@ -636,8 +639,9 @@ namespace scriptable { return obj; } - void scriptableMaterialLayerFromScriptValue(const ScriptValue &object, scriptable::ScriptableMaterialLayer& materialLayer) { + bool scriptableMaterialLayerFromScriptValue(const ScriptValue& object, scriptable::ScriptableMaterialLayer& materialLayer) { // No need to convert from ScriptValue to ScriptableMaterialLayer + return false; } ScriptValue multiMaterialMapToScriptValue(ScriptEngine* engine, const scriptable::MultiMaterialMap& map) { @@ -648,8 +652,9 @@ namespace scriptable { return obj; } - void multiMaterialMapFromScriptValue(const ScriptValue& map, scriptable::MultiMaterialMap& result) { + bool multiMaterialMapFromScriptValue(const ScriptValue& map, scriptable::MultiMaterialMap& result) { // No need to convert from ScriptValue to MultiMaterialMap + return false; } template int registerDebugEnum(ScriptEngine* engine, const DebugEnums& debugEnums) { @@ -659,8 +664,9 @@ namespace scriptable { [](ScriptEngine* engine, const T& topology) -> ScriptValue { return engine->newValue(instance.value(topology)); }, - [](const ScriptValue& value, T& topology) { + [](const ScriptValue& value, T& topology) -> bool { topology = instance.key(value.toString()); + return true; } ); } diff --git a/libraries/script-engine/src/KeyEvent.cpp b/libraries/script-engine/src/KeyEvent.cpp index a6769c41c16..1c60ba7e1e6 100644 --- a/libraries/script-engine/src/KeyEvent.cpp +++ b/libraries/script-engine/src/KeyEvent.cpp @@ -187,7 +187,7 @@ ScriptValue KeyEvent::toScriptValue(ScriptEngine* engine, const KeyEvent& event) return obj; } -void KeyEvent::fromScriptValue(const ScriptValue& object, KeyEvent& event) { +bool KeyEvent::fromScriptValue(const ScriptValue& object, KeyEvent& event) { event.isValid = false; // assume the worst event.isMeta = object.property("isMeta").toVariant().toBool(); @@ -281,6 +281,7 @@ void KeyEvent::fromScriptValue(const ScriptValue& object, KeyEvent& event) { } event.isValid = true; } + return true; } ScriptValue isShifted = object.property("isShifted"); diff --git a/libraries/script-engine/src/KeyEvent.h b/libraries/script-engine/src/KeyEvent.h index a40ece47bbf..ceccf86336f 100644 --- a/libraries/script-engine/src/KeyEvent.h +++ b/libraries/script-engine/src/KeyEvent.h @@ -30,7 +30,7 @@ class KeyEvent { operator QKeySequence() const; static ScriptValue toScriptValue(ScriptEngine* engine, const KeyEvent& event); - static void fromScriptValue(const ScriptValue& object, KeyEvent& event); + static bool fromScriptValue(const ScriptValue& object, KeyEvent& event); int key; QString text; diff --git a/libraries/script-engine/src/MIDIEvent.cpp b/libraries/script-engine/src/MIDIEvent.cpp index d25ddc7e63c..2070e7bbc9c 100644 --- a/libraries/script-engine/src/MIDIEvent.cpp +++ b/libraries/script-engine/src/MIDIEvent.cpp @@ -35,9 +35,10 @@ ScriptValue midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event) return obj; } -void midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event) { +bool midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event) { event.deltaTime = object.property(MIDI_DELTA_TIME_PROP_NAME).toVariant().toDouble(); event.type = object.property(MIDI_EVENT_TYPE_PROP_NAME).toVariant().toUInt(); event.data1 = object.property(MIDI_DATA_1_PROP_NAME).toVariant().toUInt(); event.data2 = object.property(MIDI_DATA_2_PROP_NAME).toVariant().toUInt(); + return true; } \ No newline at end of file diff --git a/libraries/script-engine/src/MIDIEvent.h b/libraries/script-engine/src/MIDIEvent.h index 1b2007cf3b5..46b1ffb8eea 100644 --- a/libraries/script-engine/src/MIDIEvent.h +++ b/libraries/script-engine/src/MIDIEvent.h @@ -33,7 +33,7 @@ Q_DECLARE_METATYPE(MIDIEvent) void registerMIDIMetaTypes(ScriptEngine* engine); ScriptValue midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event); -void midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event); +bool midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event); #endif // hifi_MIDIEvent_h diff --git a/libraries/script-engine/src/MenuItemProperties.cpp b/libraries/script-engine/src/MenuItemProperties.cpp index 9864d7dd7f8..f25d05ddf99 100644 --- a/libraries/script-engine/src/MenuItemProperties.cpp +++ b/libraries/script-engine/src/MenuItemProperties.cpp @@ -73,7 +73,7 @@ ScriptValue menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItem * @property {string} [afterItem] - The name of the menu item to place this menu item after. * @property {string} [grouping] - The name of grouping to add this menu item to. */ -void menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& properties) { +bool menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& properties) { properties.menuName = object.property("menuName").toVariant().toString(); properties.menuItemName = object.property("menuItemName").toVariant().toString(); properties.isCheckable = object.property("isCheckable").toVariant().toBool(); @@ -99,6 +99,7 @@ void menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProper properties.beforeItem = object.property("beforeItem").toVariant().toString(); properties.afterItem = object.property("afterItem").toVariant().toString(); properties.grouping = object.property("grouping").toVariant().toString(); + return true; } diff --git a/libraries/script-engine/src/MenuItemProperties.h b/libraries/script-engine/src/MenuItemProperties.h index fe36e7ce752..2cdfbad142a 100644 --- a/libraries/script-engine/src/MenuItemProperties.h +++ b/libraries/script-engine/src/MenuItemProperties.h @@ -55,7 +55,7 @@ class MenuItemProperties { }; Q_DECLARE_METATYPE(MenuItemProperties) ScriptValue menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItemProperties& props); -void menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& props); +bool menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& props); void registerMenuItemProperties(ScriptEngine* engine); diff --git a/libraries/script-engine/src/MouseEvent.cpp b/libraries/script-engine/src/MouseEvent.cpp index c436cb6f354..a0726e0aedf 100644 --- a/libraries/script-engine/src/MouseEvent.cpp +++ b/libraries/script-engine/src/MouseEvent.cpp @@ -102,6 +102,7 @@ ScriptValue MouseEvent::toScriptValue(ScriptEngine* engine, const MouseEvent& ev return obj; } -void MouseEvent::fromScriptValue(const ScriptValue& object, MouseEvent& event) { +bool MouseEvent::fromScriptValue(const ScriptValue& object, MouseEvent& event) { // nothing for now... + return false; } diff --git a/libraries/script-engine/src/MouseEvent.h b/libraries/script-engine/src/MouseEvent.h index 0d6453aee52..ffbc25854c8 100644 --- a/libraries/script-engine/src/MouseEvent.h +++ b/libraries/script-engine/src/MouseEvent.h @@ -28,7 +28,7 @@ class MouseEvent { MouseEvent(const QMouseEvent& event); static ScriptValue toScriptValue(ScriptEngine* engine, const MouseEvent& event); - static void fromScriptValue(const ScriptValue& object, MouseEvent& event); + static bool fromScriptValue(const ScriptValue& object, MouseEvent& event); ScriptValue toScriptValue(ScriptEngine* engine) const { return MouseEvent::toScriptValue(engine, *this); } diff --git a/libraries/script-engine/src/PointerEvent.cpp b/libraries/script-engine/src/PointerEvent.cpp index 87cb95fa95d..8107640a876 100644 --- a/libraries/script-engine/src/PointerEvent.cpp +++ b/libraries/script-engine/src/PointerEvent.cpp @@ -212,7 +212,7 @@ ScriptValue PointerEvent::toScriptValue(ScriptEngine* engine, const PointerEvent return obj; } -void PointerEvent::fromScriptValue(const ScriptValue& object, PointerEvent& event) { +bool PointerEvent::fromScriptValue(const ScriptValue& object, PointerEvent& event) { if (object.isObject()) { ScriptValue type = object.property("type"); QString typeStr = type.isString() ? type.toString() : "Move"; @@ -263,6 +263,7 @@ void PointerEvent::fromScriptValue(const ScriptValue& object, PointerEvent& even event._keyboardModifiers = (Qt::KeyboardModifiers)(object.property("keyboardModifiers").toUInt32()); } + return true; } static const char* typeToStringMap[PointerEvent::NumEventTypes] = { "Press", "DoublePress", "Release", "Move" }; diff --git a/libraries/script-engine/src/PointerEvent.h b/libraries/script-engine/src/PointerEvent.h index fb4617ba6eb..258cdd22e23 100644 --- a/libraries/script-engine/src/PointerEvent.h +++ b/libraries/script-engine/src/PointerEvent.h @@ -52,7 +52,7 @@ class PointerEvent { Button button = NoButtons, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::NoModifier); static ScriptValue toScriptValue(ScriptEngine* engine, const PointerEvent& event); - static void fromScriptValue(const ScriptValue& object, PointerEvent& event); + static bool fromScriptValue(const ScriptValue& object, PointerEvent& event); ScriptValue toScriptValue(ScriptEngine* engine) const { return PointerEvent::toScriptValue(engine, *this); } diff --git a/libraries/script-engine/src/ScriptContext.cpp b/libraries/script-engine/src/ScriptContext.cpp new file mode 100644 index 00000000000..16b49fe7054 --- /dev/null +++ b/libraries/script-engine/src/ScriptContext.cpp @@ -0,0 +1,23 @@ +// +// ScriptContext.h +// libraries/script-engine/src +// +// Created by Heather Anderson on 12/5/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptContext.h" + +#include "Scriptable.h" + +ScriptContextGuard::ScriptContextGuard(ScriptContext* context) { + _oldContext = Scriptable::context(); + Scriptable::setContext(context); +} + +ScriptContextGuard::~ScriptContextGuard() { + Scriptable::setContext(_oldContext); +} diff --git a/libraries/script-engine/src/ScriptContext.h b/libraries/script-engine/src/ScriptContext.h index e046fe88ca0..33c227b9a3e 100644 --- a/libraries/script-engine/src/ScriptContext.h +++ b/libraries/script-engine/src/ScriptContext.h @@ -67,6 +67,15 @@ class ScriptContext { ~ScriptContext() {} // prevent explicit deletion of base class }; +class ScriptContextGuard { +public: + ScriptContextGuard(ScriptContext* context); + ~ScriptContextGuard(); + +private: + ScriptContext* _oldContext; +}; + #endif // hifi_ScriptContext_h /// @} diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index d611e375599..9708babf831 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -49,7 +49,7 @@ class ScriptEngine { public: typedef ScriptValue (*FunctionSignature)(ScriptContext*, ScriptEngine*); typedef ScriptValue (*MarshalFunction)(ScriptEngine*, const void*); - typedef void (*DemarshalFunction)(const ScriptValue&, void*); + typedef bool (*DemarshalFunction)(const ScriptValue&, void*); enum ValueOwnership { QtOwnership = 0, @@ -136,8 +136,8 @@ class ScriptEngine { public: // not for public use, but I don't like how Qt strings this along with private friend functions virtual ScriptValue create(int type, const void* ptr) = 0; - virtual bool convert(const ScriptValue& value, int type, void* ptr) = 0; - virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df, const ScriptValue& prototype) = 0; + virtual QVariant convert(const ScriptValue& value, int type) = 0; + virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df) = 0; protected: ~ScriptEngine() {} // prevent explicit deletion of base class diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h index 475c869584c..7ab6b02f38d 100644 --- a/libraries/script-engine/src/ScriptEngineCast.h +++ b/libraries/script-engine/src/ScriptEngineCast.h @@ -42,13 +42,16 @@ inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const QV template inline T scriptvalue_cast(const ScriptValue& value) { - T t; const int id = qMetaTypeId(); auto engine = value.engine(); - if (engine && engine->convert(value, id, &t)) { - return t; - } else if (value.isVariant()) { + if (engine) { + QVariant varValue = engine->convert(value, id); + if (varValue.isValid()) { + return varValue.value(); + } + } + if (value.isVariant()) { return qvariant_cast(value.toVariant()); } @@ -63,13 +66,12 @@ inline QVariant scriptvalue_cast(const ScriptValue& value) { template int scriptRegisterMetaType(ScriptEngine* eng, ScriptValue (*toScriptValue)(ScriptEngine*, const T& t), - void (*fromScriptValue)(const ScriptValue&, T& t), - const ScriptValue& prototype = ScriptValue(), + bool (*fromScriptValue)(const ScriptValue&, T& t), T* = 0) { const int id = qRegisterMetaType(); // make sure it's registered eng->registerCustomType(id, reinterpret_cast(toScriptValue), - reinterpret_cast(fromScriptValue), prototype); + reinterpret_cast(fromScriptValue)); return id; } @@ -87,19 +89,19 @@ ScriptValue scriptValueFromSequence(ScriptEngine* eng, const Container& cont) { } template -void scriptValueToSequence(const ScriptValue& value, Container& cont) { +bool scriptValueToSequence(const ScriptValue& value, Container& cont) { quint32 len = value.property(QLatin1String("length")).toUInt32(); for (quint32 i = 0; i < len; ++i) { ScriptValue item = value.property(i); cont.push_back(scriptvalue_cast(item)); } + return true; } template int scriptRegisterSequenceMetaType(ScriptEngine* engine, - const ScriptValue& prototype = ScriptValue(), T* = 0) { - return scriptRegisterMetaType(engine, scriptValueFromSequence, scriptValueToSequence, prototype); + return scriptRegisterMetaType(engine, scriptValueFromSequence, scriptValueToSequence); } #endif // hifi_ScriptEngineCast_h diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 09f92eeec09..3d18b59197e 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -538,8 +538,9 @@ static ScriptValue scriptableResourceToScriptValue(ScriptEngine* engine, return object; } -static void scriptableResourceFromScriptValue(const ScriptValue& value, ScriptableResourceRawPtr& resource) { +static bool scriptableResourceFromScriptValue(const ScriptValue& value, ScriptableResourceRawPtr& resource) { resource = static_cast(value.toQObject()); + return true; } /*@jsdoc @@ -578,8 +579,9 @@ ScriptValue externalResourceBucketToScriptValue(ScriptEngine* engine, ExternalRe return engine->newValue((int)in); } -void externalResourceBucketFromScriptValue(const ScriptValue& object, ExternalResource::Bucket& out) { +bool externalResourceBucketFromScriptValue(const ScriptValue& object, ExternalResource::Bucket& out) { out = static_cast(object.toInt32()); + return true; } void ScriptManager::resetModuleCache(bool deleteScriptCache) { @@ -722,6 +724,11 @@ void ScriptManager::init() { })); } +// registers a global object by name +void ScriptManager::registerValue(const QString& valueName, ScriptValue value) { + _engine->globalObject().setProperty(valueName, value); +} + // Unregister the handlers for this eventName and entityID. void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QString& eventName, const ScriptValue& handler) { if (QThread::currentThread() != thread()) { diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index ea0a33a1520..8a13ea012ed 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -279,6 +279,15 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi */ Q_INVOKABLE bool isAgentScript() const { return _context == AGENT_SCRIPT; } + /*@jsdoc + * registers a global object by name. + * @function Script.registerValue + * @param {string} valueName + * @param {value} value + */ + /// registers a global object by name + Q_INVOKABLE void registerValue(const QString& valueName, ScriptValue value); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE - these are intended to be public interfaces available to scripts diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp index 4b5775d9028..da54182a9dc 100644 --- a/libraries/script-engine/src/ScriptValueUtils.cpp +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -99,7 +99,7 @@ ScriptValue vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2) { return value; } -void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2) { +bool vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2) { if (object.isNumber()) { vec2 = glm::vec2(object.toVariant().toFloat()); } else if (object.isArray()) { @@ -122,6 +122,7 @@ void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2) { vec2.x = x.toVariant().toFloat(); vec2.y = y.toVariant().toFloat(); } + return true; } ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) { @@ -174,7 +175,7 @@ ScriptValue vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) return value; } -void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) { +bool vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) { if (object.isNumber()) { vec3 = glm::vec3(object.toVariant().toFloat()); } else if (object.isString()) { @@ -220,6 +221,7 @@ void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) { vec3.y = y.toVariant().toFloat(); vec3.z = z.toVariant().toFloat(); } + return true; } ScriptValue u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) { @@ -272,7 +274,7 @@ ScriptValue u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& ve return value; } -void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3) { +bool u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3) { if (object.isNumber()) { vec3 = glm::vec3(object.toVariant().toUInt()); } else if (object.isString()) { @@ -318,6 +320,7 @@ void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3) { vec3.y = y.toVariant().toUInt(); vec3.z = z.toVariant().toUInt(); } + return true; } ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) { @@ -329,11 +332,12 @@ ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) { return obj; } -void vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4) { +bool vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4) { vec4.x = object.property("x").toVariant().toFloat(); vec4.y = object.property("y").toVariant().toFloat(); vec4.z = object.property("z").toVariant().toFloat(); vec4.w = object.property("w").toVariant().toFloat(); + return true; } ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) { @@ -357,7 +361,7 @@ ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) { return obj; } -void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4) { +bool mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4) { mat4[0][0] = object.property("r0c0").toVariant().toFloat(); mat4[0][1] = object.property("r1c0").toVariant().toFloat(); mat4[0][2] = object.property("r2c0").toVariant().toFloat(); @@ -374,6 +378,7 @@ void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4) { mat4[3][1] = object.property("r1c3").toVariant().toFloat(); mat4[3][2] = object.property("r2c3").toVariant().toFloat(); mat4[3][3] = object.property("r3c3").toVariant().toFloat(); + return true; } ScriptValue qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector& vector) { @@ -404,7 +409,7 @@ QVector qVectorVec3FromScriptValue(const ScriptValue& array) { return newVector; } -void qVectorVec3FromScriptValue(const ScriptValue& array, QVector& vector) { +bool qVectorVec3FromScriptValue(const ScriptValue& array, QVector& vector) { int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { @@ -412,6 +417,7 @@ void qVectorVec3FromScriptValue(const ScriptValue& array, QVector& ve vec3FromScriptValue(array.property(i), newVec3); vector << newVec3; } + return true; } ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) { @@ -427,7 +433,7 @@ ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) { return obj; } -void quatFromScriptValue(const ScriptValue& object, glm::quat& quat) { +bool quatFromScriptValue(const ScriptValue& object, glm::quat& quat) { quat.x = object.property("x").toVariant().toFloat(); quat.y = object.property("y").toVariant().toFloat(); quat.z = object.property("z").toVariant().toFloat(); @@ -440,6 +446,7 @@ void quatFromScriptValue(const ScriptValue& object, glm::quat& quat) { } else { quat = glm::quat(); } + return true; } ScriptValue qVectorQuatToScriptValue(ScriptEngine* engine, const QVector& vector) { @@ -482,12 +489,13 @@ ScriptValue qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector return array; } -void qVectorQUuidFromScriptValue(const ScriptValue& array, QVector& vector) { +bool qVectorQUuidFromScriptValue(const ScriptValue& array, QVector& vector) { int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { vector << array.property(i).toVariant().toUuid(); } + return true; } QVector qVectorQUuidFromScriptValue(const ScriptValue& array) { @@ -523,20 +531,22 @@ ScriptValue qVectorIntToScriptValue(ScriptEngine* engine, const QVector& vector) { +bool qVectorFloatFromScriptValue(const ScriptValue& array, QVector& vector) { int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { vector << array.property(i).toVariant().toFloat(); } + return true; } -void qVectorIntFromScriptValue(const ScriptValue& array, QVector& vector) { +bool qVectorIntFromScriptValue(const ScriptValue& array, QVector& vector) { int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { vector << array.property(i).toVariant().toInt(); } + return true; } QVector qVectorQuatFromScriptValue(const ScriptValue& array) { @@ -551,7 +561,7 @@ QVector qVectorQuatFromScriptValue(const ScriptValue& array) { return newVector; } -void qVectorQuatFromScriptValue(const ScriptValue& array, QVector& vector) { +bool qVectorQuatFromScriptValue(const ScriptValue& array, QVector& vector) { int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { @@ -559,6 +569,7 @@ void qVectorQuatFromScriptValue(const ScriptValue& array, QVector& ve quatFromScriptValue(array.property(i), newQuat); vector << newQuat; } + return true; } QVector qVectorBoolFromScriptValue(const ScriptValue& array) { @@ -571,12 +582,13 @@ QVector qVectorBoolFromScriptValue(const ScriptValue& array) { return newVector; } -void qVectorBoolFromScriptValue(const ScriptValue& array, QVector& vector) { +bool qVectorBoolFromScriptValue(const ScriptValue& array, QVector& vector) { int length = array.property("length").toInteger(); for (int i = 0; i < length; i++) { vector << array.property(i).toBool(); } + return true; } ScriptValue qRectToScriptValue(ScriptEngine* engine, const QRect& rect) { @@ -588,11 +600,12 @@ ScriptValue qRectToScriptValue(ScriptEngine* engine, const QRect& rect) { return obj; } -void qRectFromScriptValue(const ScriptValue& object, QRect& rect) { +bool qRectFromScriptValue(const ScriptValue& object, QRect& rect) { rect.setX(object.property("x").toVariant().toInt()); rect.setY(object.property("y").toVariant().toInt()); rect.setWidth(object.property("width").toVariant().toInt()); rect.setHeight(object.property("height").toVariant().toInt()); + return true; } ScriptValue qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect) { @@ -604,11 +617,12 @@ ScriptValue qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect) { return obj; } -void qRectFFromScriptValue(const ScriptValue& object, QRectF& rect) { +bool qRectFFromScriptValue(const ScriptValue& object, QRectF& rect) { rect.setX(object.property("x").toVariant().toFloat()); rect.setY(object.property("y").toVariant().toFloat()); rect.setWidth(object.property("width").toVariant().toFloat()); rect.setHeight(object.property("height").toVariant().toFloat()); + return true; } ScriptValue qColorToScriptValue(ScriptEngine* engine, const QColor& color) { @@ -639,7 +653,7 @@ ScriptValue aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube) { return obj; } -void aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube) { +bool aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube) { glm::vec3 corner; corner.x = object.property("x").toVariant().toFloat(); corner.y = object.property("y").toVariant().toFloat(); @@ -647,9 +661,10 @@ void aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube) { float scale = object.property("scale").toVariant().toFloat(); aaCube.setBox(corner, scale); + return true; } -void qColorFromScriptValue(const ScriptValue& object, QColor& color) { +bool qColorFromScriptValue(const ScriptValue& object, QColor& color) { if (object.isNumber()) { color.setRgb(object.toUInt32()); @@ -661,14 +676,16 @@ void qColorFromScriptValue(const ScriptValue& object, QColor& color) { color.setRgb(object.property("red").toInt32(), object.property("green").toInt32(), object.property("blue").toInt32(), alphaValue.isNumber() ? alphaValue.toInt32() : 255); } + return true; } ScriptValue qURLToScriptValue(ScriptEngine* engine, const QUrl& url) { return engine->newValue(url.toString()); } -void qURLFromScriptValue(const ScriptValue& object, QUrl& url) { +bool qURLFromScriptValue(const ScriptValue& object, QUrl& url) { url = object.toString(); + return true; } ScriptValue pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay) { @@ -680,7 +697,7 @@ ScriptValue pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay) { return obj; } -void pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay) { +bool pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay) { ScriptValue originValue = object.property("origin"); if (originValue.isValid()) { auto x = originValue.property("x"); @@ -703,6 +720,7 @@ void pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay) { pickRay.direction.z = z.toVariant().toFloat(); } } + return true; } /*@jsdoc @@ -726,8 +744,9 @@ ScriptValue collisionToScriptValue(ScriptEngine* engine, const Collision& collis return obj; } -void collisionFromScriptValue(const ScriptValue& object, Collision& collision) { +bool collisionFromScriptValue(const ScriptValue& object, Collision& collision) { // TODO: implement this when we know what it means to accept collision events from JS + return false; } ScriptValue quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid) { @@ -738,14 +757,15 @@ ScriptValue quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid) { return obj; } -void quuidFromScriptValue(const ScriptValue& object, QUuid& uuid) { +bool quuidFromScriptValue(const ScriptValue& object, QUuid& uuid) { if (object.isNull()) { uuid = QUuid(); - return; + return true; } QString uuidAsString = object.toVariant().toString(); QUuid fromString(uuidAsString); uuid = fromString; + return true; } /*@jsdoc @@ -761,9 +781,10 @@ ScriptValue qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF) { return obj; } -void qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF) { +bool qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF) { qSizeF.setWidth(object.property("width").toVariant().toFloat()); qSizeF.setHeight(object.property("height").toVariant().toFloat()); + return true; } /*@jsdoc @@ -802,16 +823,18 @@ ScriptValue animationDetailsToScriptValue(ScriptEngine* engine, const AnimationD return obj; } -void animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& details) { +bool animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& details) { // nothing for now... + return false; } ScriptValue meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in) { return engine->newQObject(in, ScriptEngine::QtOwnership); } -void meshFromScriptValue(const ScriptValue& value, MeshProxy*& out) { +bool meshFromScriptValue(const ScriptValue& value, MeshProxy*& out) { out = qobject_cast(value.toQObject()); + return true; } ScriptValue meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in) { @@ -822,7 +845,7 @@ ScriptValue meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in) { return result; } -void meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out) { +bool meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out) { ScriptValueIteratorPointer itr(value.newIterator()); qDebug() << "in meshesFromScriptValue, value.length =" << value.property("length").toInt32(); @@ -836,6 +859,7 @@ void meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out) { qDebug() << "null meshProxy"; } } + return true; } /*@jsdoc @@ -849,8 +873,8 @@ ScriptValue meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace return obj; } -void meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult) { - qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices); +bool meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult) { + return qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices); } ScriptValue qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& vector) { @@ -861,7 +885,7 @@ ScriptValue qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& result) { +bool qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector& result) { int length = array.property("length").toInteger(); result.clear(); @@ -870,18 +894,21 @@ void qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector& meshFaceFromScriptValue(array.property(i), meshFace); result << meshFace; } + return true; } ScriptValue stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode) { return engine->newValue((int)stencilMode); } -void stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode) { +bool stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode) { stencilMode = StencilMaskMode(object.toVariant().toInt()); + return true; } -void promiseFromScriptValue(const ScriptValue& object, std::shared_ptr& promise) { +bool promiseFromScriptValue(const ScriptValue& object, std::shared_ptr& promise) { Q_ASSERT(false); + return false; } ScriptValue promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise) { return engine->newQObject(promise.get()); @@ -891,8 +918,8 @@ ScriptValue EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& return quuidToScriptValue(engine, id); } -void EntityItemIDfromScriptValue(const ScriptValue &object, EntityItemID& id) { - quuidFromScriptValue(object, id); +bool EntityItemIDfromScriptValue(const ScriptValue& object, EntityItemID& id) { + return quuidFromScriptValue(object, id); } QVector qVectorEntityItemIDFromScriptValue(const ScriptValue& array) { diff --git a/libraries/script-engine/src/ScriptValueUtils.h b/libraries/script-engine/src/ScriptValueUtils.h index 6b478ea36f3..9773a0e58b8 100644 --- a/libraries/script-engine/src/ScriptValueUtils.h +++ b/libraries/script-engine/src/ScriptValueUtils.h @@ -52,7 +52,7 @@ void registerMetaTypes(ScriptEngine* engine); * @property {number} r3c3 - Row 3, column 3 value. */ ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4); -void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4); +bool mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4); /*@jsdoc * A 2-dimensional vector. @@ -69,7 +69,7 @@ void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4); * color.v = 0.8; // { x: 0.7, y: 0.8 } */ ScriptValue vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2); -void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2); +bool vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2); /*@jsdoc * A 3-dimensional vector. See also the {@link Vec3(0)|Vec3} object. @@ -93,7 +93,7 @@ void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2); */ ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3); ScriptValue vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3); -void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3); +bool vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3); /*@jsdoc * A color vector. See also the {@link Vec3(0)|Vec3} object. @@ -135,7 +135,7 @@ void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3); */ ScriptValue u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3); ScriptValue u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3); -void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3); +bool u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3); /*@jsdoc * A 4-dimensional vector. @@ -147,11 +147,11 @@ void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3); * @property {number} w - W-coordinate of the vector. */ ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4); -void vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4); +bool vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4); // Quaternions ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat); -void quatFromScriptValue(const ScriptValue& object, glm::quat& quat); +bool quatFromScriptValue(const ScriptValue& object, glm::quat& quat); /*@jsdoc * Defines a rectangular portion of an image or screen, or similar. @@ -163,63 +163,63 @@ void quatFromScriptValue(const ScriptValue& object, glm::quat& quat); */ class QRect; ScriptValue qRectToScriptValue(ScriptEngine* engine, const QRect& rect); -void qRectFromScriptValue(const ScriptValue& object, QRect& rect); +bool qRectFromScriptValue(const ScriptValue& object, QRect& rect); class QRectF; ScriptValue qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect); -void qRectFFromScriptValue(const ScriptValue& object, QRectF& rect); +bool qRectFFromScriptValue(const ScriptValue& object, QRectF& rect); // QColor class QColor; ScriptValue qColorToScriptValue(ScriptEngine* engine, const QColor& color); -void qColorFromScriptValue(const ScriptValue& object, QColor& color); +bool qColorFromScriptValue(const ScriptValue& object, QColor& color); class QUrl; ScriptValue qURLToScriptValue(ScriptEngine* engine, const QUrl& url); -void qURLFromScriptValue(const ScriptValue& object, QUrl& url); +bool qURLFromScriptValue(const ScriptValue& object, QUrl& url); // vector Q_DECLARE_METATYPE(QVector) ScriptValue qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector& vector); ScriptValue qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorVec3FromScriptValue(const ScriptValue& array, QVector& vector); +bool qVectorVec3FromScriptValue(const ScriptValue& array, QVector& vector); QVector qVectorVec3FromScriptValue(const ScriptValue& array); // vector Q_DECLARE_METATYPE(QVector) ScriptValue qVectorQuatToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorQuatFromScriptValue(const ScriptValue& array, QVector& vector); +bool qVectorQuatFromScriptValue(const ScriptValue& array, QVector& vector); QVector qVectorQuatFromScriptValue(const ScriptValue& array); // vector ScriptValue qVectorBoolToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorBoolFromScriptValue(const ScriptValue& array, QVector& vector); +bool qVectorBoolFromScriptValue(const ScriptValue& array, QVector& vector); QVector qVectorBoolFromScriptValue(const ScriptValue& array); // vector ScriptValue qVectorFloatToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorFloatFromScriptValue(const ScriptValue& array, QVector& vector); +bool qVectorFloatFromScriptValue(const ScriptValue& array, QVector& vector); QVector qVectorFloatFromScriptValue(const ScriptValue& array); // vector ScriptValue qVectorIntToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorIntFromScriptValue(const ScriptValue& array, QVector& vector); +bool qVectorIntFromScriptValue(const ScriptValue& array, QVector& vector); ScriptValue qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorQUuidFromScriptValue(const ScriptValue& array, QVector& vector); +bool qVectorQUuidFromScriptValue(const ScriptValue& array, QVector& vector); QVector qVectorQUuidFromScriptValue(const ScriptValue& array); class AACube; ScriptValue aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube); -void aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube); +bool aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube); class PickRay; ScriptValue pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay); -void pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay); +bool pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay); class Collision; ScriptValue collisionToScriptValue(ScriptEngine* engine, const Collision& collision); -void collisionFromScriptValue(const ScriptValue& object, Collision& collision); +bool collisionFromScriptValue(const ScriptValue& object, Collision& collision); /*@jsdoc * UUIDs (Universally Unique IDentifiers) are used to uniquely identify entities, avatars, and the like. They are represented @@ -229,42 +229,42 @@ void collisionFromScriptValue(const ScriptValue& object, Collision& collision); */ //Q_DECLARE_METATYPE(QUuid) // don't need to do this for QUuid since it's already a meta type ScriptValue quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid); -void quuidFromScriptValue(const ScriptValue& object, QUuid& uuid); +bool quuidFromScriptValue(const ScriptValue& object, QUuid& uuid); //Q_DECLARE_METATYPE(QSizeF) // Don't need to to this becase it's arleady a meta type class QSizeF; ScriptValue qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF); -void qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF); +bool qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF); class AnimationDetails; ScriptValue animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& event); -void animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& event); +bool animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& event); class MeshProxy; ScriptValue meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in); -void meshFromScriptValue(const ScriptValue& value, MeshProxy*& out); +bool meshFromScriptValue(const ScriptValue& value, MeshProxy*& out); class MeshProxyList; ScriptValue meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in); -void meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out); +bool meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out); class MeshFace; ScriptValue meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace); -void meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult); +bool meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult); ScriptValue qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector& vector); -void qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector& result); +bool qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector& result); enum class StencilMaskMode; ScriptValue stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode); -void stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode); +bool stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode); class MiniPromise; -void promiseFromScriptValue(const ScriptValue& object, std::shared_ptr& promise); +bool promiseFromScriptValue(const ScriptValue& object, std::shared_ptr& promise); ScriptValue promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr& promise); class EntityItemID; ScriptValue EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& properties); -void EntityItemIDfromScriptValue(const ScriptValue& object, EntityItemID& properties); +bool EntityItemIDfromScriptValue(const ScriptValue& object, EntityItemID& properties); QVector qVectorEntityItemIDFromScriptValue(const ScriptValue& array); #endif // #define hifi_ScriptValueUtils_h diff --git a/libraries/script-engine/src/SpatialEvent.cpp b/libraries/script-engine/src/SpatialEvent.cpp index bada11b66e7..d663fae306b 100644 --- a/libraries/script-engine/src/SpatialEvent.cpp +++ b/libraries/script-engine/src/SpatialEvent.cpp @@ -44,6 +44,7 @@ ScriptValue SpatialEvent::toScriptValue(ScriptEngine* engine, const SpatialEvent return obj; } -void SpatialEvent::fromScriptValue(const ScriptValue& object,SpatialEvent& event) { +bool SpatialEvent::fromScriptValue(const ScriptValue& object, SpatialEvent& event) { // nothing for now... + return false; } diff --git a/libraries/script-engine/src/SpatialEvent.h b/libraries/script-engine/src/SpatialEvent.h index be7e5d33202..bfd9142b932 100644 --- a/libraries/script-engine/src/SpatialEvent.h +++ b/libraries/script-engine/src/SpatialEvent.h @@ -29,7 +29,7 @@ class SpatialEvent { SpatialEvent(const SpatialEvent& other); static ScriptValue toScriptValue(ScriptEngine* engine, const SpatialEvent& event); - static void fromScriptValue(const ScriptValue& object, SpatialEvent& event); + static bool fromScriptValue(const ScriptValue& object, SpatialEvent& event); glm::vec3 locTranslation; glm::quat locRotation; diff --git a/libraries/script-engine/src/TouchEvent.cpp b/libraries/script-engine/src/TouchEvent.cpp index 593eb326fc7..d65b585b0ae 100644 --- a/libraries/script-engine/src/TouchEvent.cpp +++ b/libraries/script-engine/src/TouchEvent.cpp @@ -245,6 +245,7 @@ ScriptValue TouchEvent::toScriptValue(ScriptEngine* engine, const TouchEvent& ev return obj; } -void TouchEvent::fromScriptValue(const ScriptValue& object, TouchEvent& event) { +bool TouchEvent::fromScriptValue(const ScriptValue& object, TouchEvent& event) { // nothing for now... + return false; } diff --git a/libraries/script-engine/src/TouchEvent.h b/libraries/script-engine/src/TouchEvent.h index 3a0861b4e7f..81d093f4e1e 100644 --- a/libraries/script-engine/src/TouchEvent.h +++ b/libraries/script-engine/src/TouchEvent.h @@ -32,7 +32,7 @@ class TouchEvent { TouchEvent(const QTouchEvent& event, const TouchEvent& other); static ScriptValue toScriptValue(ScriptEngine* engine, const TouchEvent& event); - static void fromScriptValue(const ScriptValue& object, TouchEvent& event); + static bool fromScriptValue(const ScriptValue& object, TouchEvent& event); float x; float y; diff --git a/libraries/script-engine/src/WebSocketClass.cpp b/libraries/script-engine/src/WebSocketClass.cpp index 8bb6e630822..fbe2b7fc063 100644 --- a/libraries/script-engine/src/WebSocketClass.cpp +++ b/libraries/script-engine/src/WebSocketClass.cpp @@ -208,22 +208,25 @@ ScriptValue qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProt return engine->newValue(closeCode); } -void qWSCloseCodeFromScriptValue(const ScriptValue &object, QWebSocketProtocol::CloseCode &closeCode) { +bool qWSCloseCodeFromScriptValue(const ScriptValue &object, QWebSocketProtocol::CloseCode &closeCode) { closeCode = (QWebSocketProtocol::CloseCode)object.toUInt16(); + return true; } ScriptValue webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in) { return engine->newQObject(in, ScriptEngine::ScriptOwnership); } -void webSocketFromScriptValue(const ScriptValue &object, WebSocketClass* &out) { +bool webSocketFromScriptValue(const ScriptValue &object, WebSocketClass* &out) { out = qobject_cast(object.toQObject()); + return true; } ScriptValue wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState) { return engine->newValue(readyState); } -void wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState) { +bool wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState) { readyState = (WebSocketClass::ReadyState)object.toUInt16(); + return true; } diff --git a/libraries/script-engine/src/WebSocketClass.h b/libraries/script-engine/src/WebSocketClass.h index f89d30a2c9d..f0b37579e1a 100644 --- a/libraries/script-engine/src/WebSocketClass.h +++ b/libraries/script-engine/src/WebSocketClass.h @@ -253,13 +253,13 @@ Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode); Q_DECLARE_METATYPE(WebSocketClass::ReadyState); ScriptValue qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProtocol::CloseCode& closeCode); -void qWSCloseCodeFromScriptValue(const ScriptValue& object, QWebSocketProtocol::CloseCode& closeCode); +bool qWSCloseCodeFromScriptValue(const ScriptValue& object, QWebSocketProtocol::CloseCode& closeCode); ScriptValue webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in); -void webSocketFromScriptValue(const ScriptValue &object, WebSocketClass* &out); +bool webSocketFromScriptValue(const ScriptValue& object, WebSocketClass*& out); ScriptValue wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState); -void wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState); +bool wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState); #endif // hifi_WebSocketClass_h diff --git a/libraries/script-engine/src/WheelEvent.cpp b/libraries/script-engine/src/WheelEvent.cpp index 4cf238e65b4..e22e04d078b 100644 --- a/libraries/script-engine/src/WheelEvent.cpp +++ b/libraries/script-engine/src/WheelEvent.cpp @@ -97,6 +97,7 @@ ScriptValue WheelEvent::toScriptValue(ScriptEngine* engine, const WheelEvent& ev return obj; } -void WheelEvent::fromScriptValue(const ScriptValue& object, WheelEvent& event) { +bool WheelEvent::fromScriptValue(const ScriptValue& object, WheelEvent& event) { // nothing for now... + return false; } diff --git a/libraries/script-engine/src/WheelEvent.h b/libraries/script-engine/src/WheelEvent.h index 74421cb10e9..35a3dc3c04a 100644 --- a/libraries/script-engine/src/WheelEvent.h +++ b/libraries/script-engine/src/WheelEvent.h @@ -29,7 +29,7 @@ class WheelEvent { WheelEvent(const QWheelEvent& event); static ScriptValue toScriptValue(ScriptEngine* engine, const WheelEvent& event); - static void fromScriptValue(const ScriptValue& object, WheelEvent& event); + static bool fromScriptValue(const ScriptValue& object, WheelEvent& event); int x; int y; diff --git a/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp b/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp index 3902096e52f..85564bc114b 100644 --- a/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp +++ b/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp @@ -87,7 +87,8 @@ QScriptValue ArrayBufferClass::newInstance(qint32 size) { } QScriptValue ArrayBufferClass::newInstance(const QByteArray& ba) { - QScriptValue data = engine()->newVariant(QVariant::fromValue(ba)); + QScriptEngine* eng = engine(); + QScriptValue data = eng->newVariant(QVariant::fromValue(ba)); return engine()->newObject(this, data); } diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index c2c25f9bb8b..e5ce15898bf 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -49,17 +49,13 @@ #include "../ScriptValue.h" #include "ScriptContextQtWrapper.h" +#include "ScriptObjectQtProxy.h" #include "ScriptProgramQtWrapper.h" #include "ScriptValueQtWrapper.h" #include "ScriptContextQtAgent.h" static const int MAX_DEBUG_VALUE_LENGTH { 80 }; -static const QScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS = - QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects; - -Q_DECLARE_METATYPE(ScriptValue); - Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) int qfunctionSignatureMetaID = qRegisterMetaType(); @@ -311,21 +307,12 @@ void ScriptEngineQtScript::_debugDump(const QString& header, const QScriptValue& } #endif -static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValue& src) { - return ScriptValueQtWrapper::fullUnwrap(static_cast(engine), src); -} - -static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValue& dest) { - ScriptEngineQtScript* engine = static_cast(src.engine()); - dest = ScriptValue(new ScriptValueQtWrapper(engine, src)); -} - ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : QScriptEngine(), _scriptManager(scriptManager), _arrayBufferClass(new ArrayBufferClass(this)) { - qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue); + registerSystemTypes(); if (_scriptManager) { connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { @@ -343,10 +330,10 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : } QScriptValue null = QScriptEngine::nullValue(); - _nullValue = ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(null))); + _nullValue = ScriptValue(new ScriptValueQtWrapper(this, std::move(null))); QScriptValue undefined = QScriptEngine::undefinedValue(); - _undefinedValue = ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(undefined))); + _undefinedValue = ScriptValue(new ScriptValueQtWrapper(this, std::move(undefined))); QScriptEngine::setProcessEventsInterval(MSECS_PER_SECOND); @@ -417,7 +404,7 @@ void ScriptEngineQtScript::registerGlobalObject(const QString& name, QObject* ob if (!QScriptEngine::globalObject().property(name).isValid()) { if (object) { - QScriptValue value = QScriptEngine::newQObject(object, QScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS); + QScriptValue value = ScriptObjectQtProxy::newQObject(this, object, ScriptEngine::QtOwnership); QScriptEngine::globalObject().setProperty(name, value); } else { QScriptEngine::globalObject().setProperty(name, QScriptValue()); @@ -747,7 +734,7 @@ void ScriptEngineQtScript::updateMemoryCost(const qint64& deltaSize) { ScriptValue ScriptEngineQtScript::globalObject() const { QScriptValue global = QScriptEngine::globalObject(); // can't cache the value as it may change - return ScriptValue(new ScriptValueQtWrapper(const_cast < ScriptEngineQtScript*>(this), std::move(global))); + return ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(global))); } ScriptManager* ScriptEngineQtScript::manager() const { @@ -783,8 +770,7 @@ ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode, ScriptValue ScriptEngineQtScript::newQObject(QObject* object, ScriptEngine::ValueOwnership ownership, const ScriptEngine::QObjectWrapOptions& options) { - QScriptValue result = QScriptEngine::newQObject(object, static_cast(ownership), - (QScriptEngine::QObjectWrapOptions)((int)options | DEFAULT_QOBJECT_WRAP_OPTIONS)); + QScriptValue result = ScriptObjectQtProxy::newQObject(this, object, ownership, options); return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } @@ -824,7 +810,7 @@ ScriptValue ScriptEngineQtScript::newValue(const char* value) { } ScriptValue ScriptEngineQtScript::newVariant(const QVariant& value) { - QScriptValue result = QScriptEngine::newVariant(value); + QScriptValue result = castVariantToValue(value); return ScriptValue(new ScriptValueQtWrapper(this, std::move(result))); } @@ -832,13 +818,6 @@ ScriptValue ScriptEngineQtScript::nullValue() { return _nullValue; } -void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValue& prototype){ - ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype); - if (unwrappedPrototype) { - QScriptEngine::setDefaultPrototype(metaTypeId, unwrappedPrototype->toQtValue()); - } -} - ScriptValue ScriptEngineQtScript::undefinedValue() { return _undefinedValue; } @@ -928,112 +907,26 @@ bool ScriptEngineQtScript::raiseException(const ScriptValue& exception) { } ScriptValue ScriptEngineQtScript::create(int type, const void* ptr) { - QScriptValue result = qScriptValueFromValue_helper(this, type, ptr); - return ScriptValue(new ScriptValueQtWrapper(const_cast(this), std::move(result))); + QVariant variant(type, ptr); + QScriptValue scriptValue = castVariantToValue(variant); + return ScriptValue(new ScriptValueQtWrapper(this, std::move(scriptValue))); } -bool ScriptEngineQtScript::convert(const ScriptValue& value, int type, void* ptr) { +QVariant ScriptEngineQtScript::convert(const ScriptValue& value, int type) { ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); if (unwrapped == nullptr) { - return false; + return QVariant(); } - return qscriptvalue_cast_helper(unwrapped->toQtValue(), type, ptr); -} -template -class CustomTypeInstance { -public: - static ScriptEngine::MarshalFunction marshalFunc; - static ScriptEngine::DemarshalFunction demarshalFunc; - - static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) { - ScriptEngineQtScript* unwrappedEngine = static_cast(engine); - ScriptValue dest = marshalFunc(unwrappedEngine, src); - return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest); - } - - static void internalDemarshalFunc(const QScriptValue& src, void* dest) { - ScriptEngineQtScript* unwrappedEngine = static_cast(src.engine()); - ScriptValue wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src)); - demarshalFunc(wrappedSrc, dest); - } -}; -template -ScriptEngine::MarshalFunction CustomTypeInstance::marshalFunc; -template -ScriptEngine::DemarshalFunction CustomTypeInstance::demarshalFunc; - -// I would *LOVE* it if there was a different way to do this, jeez! -// Qt requires two functions that have no parameters that give any context, -// one of the must return a QScriptValue (so we can't void* them into generics and stick them in the templates). -// This *has* to be done via templates but the whole point of this is to avoid leaking types into the rest of -// the system that would require anyone other than us to have a dependency on QtScript -#define CUSTOM_TYPE_ENTRY(idx) \ - case idx: \ - CustomTypeInstance::marshalFunc = marshalFunc; \ - CustomTypeInstance::demarshalFunc = demarshalFunc; \ - internalMarshalFunc = CustomTypeInstance::internalMarshalFunc; \ - internalDemarshalFunc = CustomTypeInstance::internalDemarshalFunc; \ - break; -#define CUSTOM_TYPE_ENTRY_10(idx) \ - CUSTOM_TYPE_ENTRY((idx * 10)); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 1); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 2); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 3); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 4); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 5); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 6); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 7); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 8); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 9); - -void ScriptEngineQtScript::registerCustomType(int type, - ScriptEngine::MarshalFunction marshalFunc, - ScriptEngine::DemarshalFunction demarshalFunc, - const ScriptValue& prototype) -{ - QScriptValue unwrapped = ScriptValueQtWrapper::fullUnwrap(this, prototype); - QScriptEngine::MarshalFunction internalMarshalFunc; - QScriptEngine::DemarshalFunction internalDemarshalFunc; + QVariant var; + if (!castValueToVariant(unwrapped->toQtValue(), var, type)) { + return QVariant(); + } - if (_nextCustomType >= 300) { // have we ran out of translators? - Q_ASSERT(false); - return; + int destType = var.userType(); + if (destType != type) { + var.convert(type); // if conversion fails then var is set to QVariant() } - switch (_nextCustomType++) { - CUSTOM_TYPE_ENTRY_10(0); - CUSTOM_TYPE_ENTRY_10(1); - CUSTOM_TYPE_ENTRY_10(2); - CUSTOM_TYPE_ENTRY_10(3); - CUSTOM_TYPE_ENTRY_10(4); - CUSTOM_TYPE_ENTRY_10(5); - CUSTOM_TYPE_ENTRY_10(6); - CUSTOM_TYPE_ENTRY_10(7); - CUSTOM_TYPE_ENTRY_10(8); - CUSTOM_TYPE_ENTRY_10(9); - CUSTOM_TYPE_ENTRY_10(10); - CUSTOM_TYPE_ENTRY_10(11); - CUSTOM_TYPE_ENTRY_10(12); - CUSTOM_TYPE_ENTRY_10(13); - CUSTOM_TYPE_ENTRY_10(14); - CUSTOM_TYPE_ENTRY_10(15); - CUSTOM_TYPE_ENTRY_10(16); - CUSTOM_TYPE_ENTRY_10(17); - CUSTOM_TYPE_ENTRY_10(18); - CUSTOM_TYPE_ENTRY_10(19); - CUSTOM_TYPE_ENTRY_10(20); - CUSTOM_TYPE_ENTRY_10(21); - CUSTOM_TYPE_ENTRY_10(22); - CUSTOM_TYPE_ENTRY_10(23); - CUSTOM_TYPE_ENTRY_10(24); - CUSTOM_TYPE_ENTRY_10(25); - CUSTOM_TYPE_ENTRY_10(26); - CUSTOM_TYPE_ENTRY_10(27); - CUSTOM_TYPE_ENTRY_10(28); - CUSTOM_TYPE_ENTRY_10(29); - CUSTOM_TYPE_ENTRY_10(30); - } - - qScriptRegisterMetaType_helper(this, type, internalMarshalFunc, internalDemarshalFunc, unwrapped); + return var; } diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 9d1e54d1b35..5dd685292f2 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -19,7 +19,9 @@ #include #include +#include #include +#include #include #include #include @@ -148,10 +150,11 @@ class ScriptEngineQtScript final : public QScriptEngine, public: // not for public use, but I don't like how Qt strings this along with private friend functions virtual ScriptValue create(int type, const void* ptr) override; - virtual bool convert(const ScriptValue& value, int type, void* ptr) override; + virtual QVariant convert(const ScriptValue& value, int type) override; virtual void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, - ScriptEngine::DemarshalFunction demarshalFunc, - const ScriptValue& prototype) override; + ScriptEngine::DemarshalFunction demarshalFunc) override; + bool castValueToVariant(const QScriptValue& val, QVariant& dest, int destType); + QScriptValue castVariantToValue(const QVariant& val); protected: // like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues @@ -162,9 +165,21 @@ class ScriptEngineQtScript final : public QScriptEngine, const QScriptValue& data = QScriptValue(), const QScriptEngine::ValueOwnership& ownership = QScriptEngine::AutoOwnership); + void registerSystemTypes(); + protected: + struct CustomMarshal { + ScriptEngine::MarshalFunction marshalFunc; + ScriptEngine::DemarshalFunction demarshalFunc; + }; + using CustomMarshalMap = QHash; + using CustomPrototypeMap = QHash; + QPointer _scriptManager; + mutable QMutex _customTypeProtect; + CustomMarshalMap _customTypes; + CustomPrototypeMap _customPrototypes; int _nextCustomType = 0; ScriptValue _nullValue; ScriptValue _undefinedValue; diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript_cast.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript_cast.cpp new file mode 100644 index 00000000000..69125ec6070 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript_cast.cpp @@ -0,0 +1,538 @@ +// +// ScriptEngineQtScript_cast.cpp +// libraries/script-engine/src/qtscript +// +// Created by Heather Anderson 12/9/2021 +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptEngineQtScript.h" + +#include +#include +#include +#include + +#include "../ScriptValueIterator.h" + +#include "ScriptObjectQtProxy.h" +#include "ScriptValueQtWrapper.h" + +template +class CustomTypeInstance { +public: + static ScriptEngine::MarshalFunction marshalFunc; + static ScriptEngine::DemarshalFunction demarshalFunc; + + static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) { + ScriptEngineQtScript* unwrappedEngine = static_cast(engine); + ScriptValue dest = marshalFunc(unwrappedEngine, src); + return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest); + } + + static void internalDemarshalFunc(const QScriptValue& src, void* dest) { + ScriptEngineQtScript* unwrappedEngine = static_cast(src.engine()); + ScriptValue wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src)); + demarshalFunc(wrappedSrc, dest); + } +}; +template +ScriptEngine::MarshalFunction CustomTypeInstance::marshalFunc; +template +ScriptEngine::DemarshalFunction CustomTypeInstance::demarshalFunc; + +// I would *LOVE* it if there was a different way to do this, jeez! +// Qt requires two functions that have no parameters that give any context, +// one of the must return a QScriptValue (so we can't void* them into generics and stick them in the templates). +// This *has* to be done via templates but the whole point of this is to avoid leaking types into the rest of +// the system that would require anyone other than us to have a dependency on QtScript +#define CUSTOM_TYPE_ENTRY(idx) \ + case idx: \ + CustomTypeInstance::marshalFunc = marshalFunc; \ + CustomTypeInstance::demarshalFunc = demarshalFunc; \ + internalMarshalFunc = CustomTypeInstance::internalMarshalFunc; \ + internalDemarshalFunc = CustomTypeInstance::internalDemarshalFunc; \ + break; +#define CUSTOM_TYPE_ENTRY_10(idx) \ + CUSTOM_TYPE_ENTRY((idx * 10)); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 1); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 2); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 3); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 4); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 5); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 6); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 7); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 8); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 9); + +void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) { + ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype); + if (unwrappedPrototype) { + const QScriptValue& scriptPrototype = unwrappedPrototype->toQtValue(); + QScriptEngine::setDefaultPrototype(metaTypeId, scriptPrototype); + + QMutexLocker guard(&_customTypeProtect); + _customPrototypes.insert(metaTypeId, scriptPrototype); + } +} + +void ScriptEngineQtScript::registerCustomType(int type, + ScriptEngine::MarshalFunction marshalFunc, + ScriptEngine::DemarshalFunction demarshalFunc) +{ + QScriptEngine::MarshalFunction internalMarshalFunc; + QScriptEngine::DemarshalFunction internalDemarshalFunc; + + { + QMutexLocker guard(&_customTypeProtect); + + // storing it in a map for our own benefit + CustomMarshal& customType = _customTypes.insert(type, CustomMarshal()).value(); + customType.demarshalFunc = demarshalFunc; + customType.marshalFunc = marshalFunc; + + // creating a conversion for QtScript's benefit + if (_nextCustomType >= 300) { // have we ran out of translators? + Q_ASSERT(false); + return; + } + + switch (_nextCustomType++) { + CUSTOM_TYPE_ENTRY_10(0); + CUSTOM_TYPE_ENTRY_10(1); + CUSTOM_TYPE_ENTRY_10(2); + CUSTOM_TYPE_ENTRY_10(3); + CUSTOM_TYPE_ENTRY_10(4); + CUSTOM_TYPE_ENTRY_10(5); + CUSTOM_TYPE_ENTRY_10(6); + CUSTOM_TYPE_ENTRY_10(7); + CUSTOM_TYPE_ENTRY_10(8); + CUSTOM_TYPE_ENTRY_10(9); + CUSTOM_TYPE_ENTRY_10(10); + CUSTOM_TYPE_ENTRY_10(11); + CUSTOM_TYPE_ENTRY_10(12); + CUSTOM_TYPE_ENTRY_10(13); + CUSTOM_TYPE_ENTRY_10(14); + CUSTOM_TYPE_ENTRY_10(15); + CUSTOM_TYPE_ENTRY_10(16); + CUSTOM_TYPE_ENTRY_10(17); + CUSTOM_TYPE_ENTRY_10(18); + CUSTOM_TYPE_ENTRY_10(19); + CUSTOM_TYPE_ENTRY_10(20); + CUSTOM_TYPE_ENTRY_10(21); + CUSTOM_TYPE_ENTRY_10(22); + CUSTOM_TYPE_ENTRY_10(23); + CUSTOM_TYPE_ENTRY_10(24); + CUSTOM_TYPE_ENTRY_10(25); + CUSTOM_TYPE_ENTRY_10(26); + CUSTOM_TYPE_ENTRY_10(27); + CUSTOM_TYPE_ENTRY_10(28); + CUSTOM_TYPE_ENTRY_10(29); + CUSTOM_TYPE_ENTRY_10(30); + } + } + + qScriptRegisterMetaType_helper(this, type, internalMarshalFunc, internalDemarshalFunc, QScriptValue()); +} + +Q_DECLARE_METATYPE(ScriptValue); + +static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValue& src) { + return ScriptValueQtWrapper::fullUnwrap(static_cast(engine), src); +} + +static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValue& dest) { + ScriptEngineQtScript* engine = static_cast(src.engine()); + dest = ScriptValue(new ScriptValueQtWrapper(engine, src)); +} + +static ScriptValue StringListToScriptValue(ScriptEngine* engine, const void* pSrc) { + const QStringList& src = *reinterpret_cast(pSrc); + int len = src.length(); + ScriptValue dest = engine->newArray(len); + for (int idx = 0; idx < len; ++idx) { + dest.setProperty(idx, engine->newValue(src.at(idx))); + } + return dest; +} + +static bool StringListFromScriptValue(const ScriptValue& src, void* pDest) { + if(!src.isArray()) return false; + QStringList& dest = *reinterpret_cast(pDest); + int len = src.property("length").toInteger(); + dest.clear(); + for (int idx = 0; idx < len; ++idx) { + dest.append(src.property(idx).toString()); + } + return true; +} + +static ScriptValue VariantListToScriptValue(ScriptEngine* engine, const void* pSrc) { + const QVariantList& src = *reinterpret_cast(pSrc); + int len = src.length(); + ScriptValue dest = engine->newArray(len); + for (int idx = 0; idx < len; ++idx) { + dest.setProperty(idx, engine->newVariant(src.at(idx))); + } + return dest; +} + +static bool VariantListFromScriptValue(const ScriptValue& src, void* pDest) { + if(!src.isArray()) return false; + QVariantList& dest = *reinterpret_cast(pDest); + int len = src.property("length").toInteger(); + dest.clear(); + for (int idx = 0; idx < len; ++idx) { + dest.append(src.property(idx).toVariant()); + } + return true; +} + +static ScriptValue VariantMapToScriptValue(ScriptEngine* engine, const void* pSrc) { + const QVariantMap& src = *reinterpret_cast(pSrc); + ScriptValue dest = engine->newObject(); + for (QVariantMap::const_iterator iter = src.cbegin(); iter != src.cend(); ++iter) { + dest.setProperty(iter.key(), engine->newVariant(iter.value())); + } + return dest; +} + +static bool VariantMapFromScriptValue(const ScriptValue& src, void* pDest) { + QVariantMap& dest = *reinterpret_cast(pDest); + dest.clear(); + ScriptValueIteratorPointer iter = src.newIterator(); + while (iter->hasNext()) { + iter->next(); + dest.insert(iter->name(), iter->value().toVariant()); + } + return true; +} + +static ScriptValue VariantHashToScriptValue(ScriptEngine* engine, const void* pSrc) { + const QVariantHash& src = *reinterpret_cast(pSrc); + ScriptValue dest = engine->newObject(); + for (QVariantHash::const_iterator iter = src.cbegin(); iter != src.cend(); ++iter) { + dest.setProperty(iter.key(), engine->newVariant(iter.value())); + } + return dest; +} + +static bool VariantHashFromScriptValue(const ScriptValue& src, void* pDest) { + QVariantHash& dest = *reinterpret_cast(pDest); + dest.clear(); + ScriptValueIteratorPointer iter = src.newIterator(); + while (iter->hasNext()) { + iter->next(); + dest.insert(iter->name(), iter->value().toVariant()); + } + return true; +} + +static ScriptValue JsonValueToScriptValue(ScriptEngine* engine, const void* pSrc) { + const QJsonValue& src = *reinterpret_cast(pSrc); + return engine->newVariant(src.toVariant()); +} + +static bool JsonValueFromScriptValue(const ScriptValue& src, void* pDest) { + QJsonValue& dest = *reinterpret_cast(pDest); + dest = QJsonValue::fromVariant(src.toVariant()); + return true; +} + +static ScriptValue JsonObjectToScriptValue(ScriptEngine* engine, const void* pSrc) { + const QJsonObject& src = *reinterpret_cast(pSrc); + QVariantMap map = src.toVariantMap(); + ScriptValue dest = engine->newObject(); + for (QVariantMap::const_iterator iter = map.cbegin(); iter != map.cend(); ++iter) { + dest.setProperty(iter.key(), engine->newVariant(iter.value())); + } + return dest; +} + +static bool JsonObjectFromScriptValue(const ScriptValue& src, void* pDest) { + QJsonObject& dest = *reinterpret_cast(pDest); + QVariantMap map; + ScriptValueIteratorPointer iter = src.newIterator(); + while (iter->hasNext()) { + iter->next(); + map.insert(iter->name(), iter->value().toVariant()); + } + dest = QJsonObject::fromVariantMap(map); + return true; +} + +static ScriptValue JsonArrayToScriptValue(ScriptEngine* engine, const void* pSrc) { + const QJsonArray& src = *reinterpret_cast(pSrc); + QVariantList list = src.toVariantList(); + int len = list.length(); + ScriptValue dest = engine->newArray(len); + for (int idx = 0; idx < len; ++idx) { + dest.setProperty(idx, engine->newVariant(list.at(idx))); + } + return dest; +} + +static bool JsonArrayFromScriptValue(const ScriptValue& src, void* pDest) { + if(!src.isArray()) return false; + QJsonArray& dest = *reinterpret_cast(pDest); + QVariantList list; + int len = src.property("length").toInteger(); + for (int idx = 0; idx < len; ++idx) { + list.append(src.property(idx).toVariant()); + } + dest = QJsonArray::fromVariantList(list); + return true; +} + +// QMetaType::QJsonArray + +void ScriptEngineQtScript::registerSystemTypes() { + qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue); + + QMutexLocker guard(&_customTypeProtect); + + { + CustomMarshal& customType = _customTypes.insert(QMetaType::QStringList, CustomMarshal()).value(); + customType.demarshalFunc = StringListFromScriptValue; + customType.marshalFunc = StringListToScriptValue; + } + { + CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantList, CustomMarshal()).value(); + customType.demarshalFunc = VariantListFromScriptValue; + customType.marshalFunc = VariantListToScriptValue; + } + { + CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantMap, CustomMarshal()).value(); + customType.demarshalFunc = VariantMapFromScriptValue; + customType.marshalFunc = VariantMapToScriptValue; + } + { + CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantHash, CustomMarshal()).value(); + customType.demarshalFunc = VariantHashFromScriptValue; + customType.marshalFunc = VariantHashToScriptValue; + } + { + CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonValue, CustomMarshal()).value(); + customType.demarshalFunc = JsonValueFromScriptValue; + customType.marshalFunc = JsonValueToScriptValue; + } + { + CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonObject, CustomMarshal()).value(); + customType.demarshalFunc = JsonObjectFromScriptValue; + customType.marshalFunc = JsonObjectToScriptValue; + } + { + CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonArray, CustomMarshal()).value(); + customType.demarshalFunc = JsonArrayFromScriptValue; + customType.marshalFunc = JsonArrayToScriptValue; + } +} + +bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& dest, int destType) { + + // if we're not particularly interested in a specific type, try to detect if we're dealing with a registered type + if (destType == QMetaType::UnknownType) { + QObject* obj = ScriptObjectQtProxy::unwrap(val); + if (obj) { + for (const QMetaObject* metaObject = obj->metaObject(); metaObject; metaObject = metaObject->superClass()) { + QByteArray typeName = QByteArray(metaObject->className()) + "*"; + int typeId = QMetaType::type(typeName.constData()); + if (typeId != QMetaType::UnknownType) { + destType = typeId; + break; + } + } + } + } + + if (destType == qMetaTypeId()) { + dest = QVariant::fromValue(ScriptValue(new ScriptValueQtWrapper(this, val))); + return true; + } + + // do we have a registered handler for this type? + ScriptEngine::DemarshalFunction demarshalFunc = nullptr; + { + QMutexLocker guard(&_customTypeProtect); + CustomMarshalMap::const_iterator lookup = _customTypes.find(destType); + if (lookup != _customTypes.cend()) { + demarshalFunc = lookup.value().demarshalFunc; + } + } + if (demarshalFunc) { + void* destStorage = QMetaType::create(destType); + ScriptValue wrappedVal(new ScriptValueQtWrapper(this, val)); + bool success = demarshalFunc(wrappedVal, destStorage); + dest = success ? QVariant(destType, destStorage) : QVariant(); + QMetaType::destroy(destType, destStorage); + return success; + } else { + switch (destType) { + case QMetaType::UnknownType: + if (val.isUndefined()) { + dest = QVariant(); + break; + } + if (val.isNull()) { + dest = QVariant::fromValue(nullptr); + break; + } + if (val.isBool()) { + dest = QVariant::fromValue(val.toBool()); + break; + } + if (val.isString()) { + dest = QVariant::fromValue(val.toString()); + break; + } + if (val.isNumber()) { + dest = QVariant::fromValue(val.toNumber()); + break; + } + { + QObject* obj = ScriptObjectQtProxy::unwrap(val); + if (obj) { + dest = QVariant::fromValue(obj); + break; + } + } + { + QVariant var = ScriptVariantQtProxy::unwrap(val); + if (var.isValid()) { + dest = var; + break; + } + } + dest = val.toVariant(); + break; + case QMetaType::Bool: + dest = QVariant::fromValue(val.toBool()); + break; + case QMetaType::QDateTime: + case QMetaType::QDate: + Q_ASSERT(val.isDate()); + dest = QVariant::fromValue(val.toDateTime()); + break; + case QMetaType::UInt: + case QMetaType::ULong: + dest = QVariant::fromValue(val.toUInt32()); + break; + case QMetaType::Int: + case QMetaType::Long: + case QMetaType::Short: + dest = QVariant::fromValue(val.toInt32()); + break; + case QMetaType::Double: + case QMetaType::Float: + case QMetaType::ULongLong: + case QMetaType::LongLong: + dest = QVariant::fromValue(val.toNumber()); + break; + case QMetaType::QString: + case QMetaType::QByteArray: + dest = QVariant::fromValue(val.toString()); + break; + case QMetaType::UShort: + dest = QVariant::fromValue(val.toUInt16()); + break; + case QMetaType::QObjectStar: + dest = QVariant::fromValue(ScriptObjectQtProxy::unwrap(val)); + break; + default: + // check to see if this is a pointer to a QObject-derived object + if (QMetaType::typeFlags(destType) & QMetaType::PointerToQObject) { + dest = QVariant::fromValue(ScriptObjectQtProxy::unwrap(val)); + break; + } + // check to see if we have a registered prototype + { + QVariant var = ScriptVariantQtProxy::unwrap(val); + if (var.isValid()) { + dest = var; + break; + } + } + // last chance, just convert it to a variant + dest = val.toVariant(); + break; + } + } + + return destType == QMetaType::UnknownType || dest.userType() == destType || dest.convert(destType); +} + +QScriptValue ScriptEngineQtScript::castVariantToValue(const QVariant& val) { + int valTypeId = val.userType(); + + if (valTypeId == qMetaTypeId()) { + // this is a wrapped ScriptValue, so just unwrap it and call it good + ScriptValue innerVal = val.value(); + return ScriptValueQtWrapper::fullUnwrap(this, innerVal); + } + + // do we have a registered handler for this type? + ScriptEngine::MarshalFunction marshalFunc = nullptr; + { + QMutexLocker guard(&_customTypeProtect); + CustomMarshalMap::const_iterator lookup = _customTypes.find(valTypeId); + if (lookup != _customTypes.cend()) { + marshalFunc = lookup.value().marshalFunc; + } + } + if (marshalFunc) { + ScriptValue wrappedVal = marshalFunc(this, val.constData()); + return ScriptValueQtWrapper::fullUnwrap(this, wrappedVal); + } + + switch (valTypeId) { + case QMetaType::UnknownType: + case QMetaType::Void: + return QScriptValue(this, QScriptValue::UndefinedValue); + case QMetaType::Nullptr: + return QScriptValue(this, QScriptValue::NullValue); + case QMetaType::Bool: + return QScriptValue(this, val.toBool()); + case QMetaType::Int: + case QMetaType::Long: + case QMetaType::Short: + return QScriptValue(this, val.toInt()); + case QMetaType::UInt: + case QMetaType::ULong: + case QMetaType::UShort: + return QScriptValue(this, val.toUInt()); + case QMetaType::Float: + case QMetaType::LongLong: + case QMetaType::ULongLong: + case QMetaType::Double: + return QScriptValue(this, val.toFloat()); + case QMetaType::QString: + case QMetaType::QByteArray: + return QScriptValue(this, val.toString()); + case QMetaType::QVariant: + return castVariantToValue(val.value()); + case QMetaType::QObjectStar: + return ScriptObjectQtProxy::newQObject(this, val.value(), ScriptEngine::QtOwnership); + case QMetaType::QDateTime: + return static_cast(this)->newDate(val.value()); + case QMetaType::QDate: + return static_cast(this)->newDate(val.value().startOfDay()); + default: + // check to see if this is a pointer to a QObject-derived object + if (QMetaType::typeFlags(valTypeId) & QMetaType::PointerToQObject) { + return ScriptObjectQtProxy::newQObject(this, val.value(), ScriptEngine::QtOwnership); + } + // have we set a prototype'd variant? + { + QMutexLocker guard(&_customTypeProtect); + CustomPrototypeMap::const_iterator lookup = _customPrototypes.find(valTypeId); + if (lookup != _customPrototypes.cend()) { + return ScriptVariantQtProxy::newVariant(this, val, lookup.value()); + } + } + // just do a generic variant + return QScriptEngine::newVariant(val); + } +} \ No newline at end of file diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp new file mode 100644 index 00000000000..f981534b07c --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp @@ -0,0 +1,622 @@ +// +// ScriptObjectQtProxy.cpp +// libraries/script-engine/src/qtscript +// +// Created by Heather Anderson on 12/5/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ScriptObjectQtProxy.h" + +#include +#include + +#include + +#include "ScriptContextQtWrapper.h" +#include "ScriptValueQtWrapper.h" + +Q_DECLARE_METATYPE(QScriptContext*) +Q_DECLARE_METATYPE(ScriptValue) +Q_DECLARE_METATYPE(QScriptValue) + +Q_DECLARE_METATYPE(QSharedPointer) +Q_DECLARE_METATYPE(QSharedPointer) + +// Used strictly to replace the "this" object value for property access. May expand to a full context element +// if we find it necessary to, but hopefully not needed +class ScriptPropertyContextQtWrapper final : public ScriptContext { +public: // construction + inline ScriptPropertyContextQtWrapper(const ScriptValue& object, ScriptContext* parentContext) : + _parent(parentContext), _object(object) {} + +public: // ScriptContext implementation + virtual int argumentCount() const override { return _parent->argumentCount(); } + virtual ScriptValue argument(int index) const override { return _parent->argument(index); } + virtual QStringList backtrace() const override { return _parent->backtrace(); } + virtual ScriptValue callee() const override { return _parent->callee(); } + virtual ScriptEnginePointer engine() const override { return _parent->engine(); } + virtual ScriptFunctionContextPointer functionContext() const override { return _parent->functionContext(); } + virtual ScriptContextPointer parentContext() const override { return _parent->parentContext(); } + virtual ScriptValue thisObject() const override { return _object; } + virtual ScriptValue throwError(const QString& text) override { return _parent->throwError(text); } + virtual ScriptValue throwValue(const ScriptValue& value) override { return _parent->throwValue(value); } + +private: // storage + ScriptContext* _parent; + const ScriptValue& _object; +}; + +QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObject* object, + ScriptEngine::ValueOwnership ownership, + const ScriptEngine::QObjectWrapOptions& options) { + bool ownsObject; + switch (ownership) { + case ScriptEngine::QtOwnership: + ownsObject = false; + break; + case ScriptEngine::ScriptOwnership: + ownsObject = true; + break; + case ScriptEngine::AutoOwnership: + ownsObject = !object->parent(); + break; + } + QScriptEngine* qengine = static_cast(engine); + auto proxy = QSharedPointer::create(engine, object, ownsObject, options); + return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); +} + +ScriptObjectQtProxy* ScriptObjectQtProxy::unwrapProxy(const QScriptValue& val) { + QScriptClass* scriptClass = val.scriptClass(); + return scriptClass ? dynamic_cast(scriptClass) : nullptr; +} + +QObject* ScriptObjectQtProxy::unwrap(const QScriptValue& val) { + if (val.isQObject()) { + return val.toQObject(); + } + ScriptObjectQtProxy* proxy = unwrapProxy(val); + return proxy ? proxy->toQtValue() : nullptr; +} + +ScriptObjectQtProxy::~ScriptObjectQtProxy() { + if (_ownsObject) { + QObject* qobject = _object; + if(qobject) qobject->deleteLater(); + } +} + +void ScriptObjectQtProxy::investigate() { + QObject* qobject = _object; + Q_ASSERT(qobject); + if (!qobject) return; + + const QMetaObject* metaObject = qobject->metaObject(); + _name = QString::fromLatin1(metaObject->className()); + + // discover properties + int startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassProperties ? metaObject->propertyOffset() : 0; + int num = metaObject->propertyCount(); + for (int idx = startIdx; idx < num; ++idx) { + QMetaProperty prop = metaObject->property(idx); + if (!prop.isScriptable()) continue; + + // always exclude child objects (at least until we decide otherwise) + int metaTypeId = prop.userType(); + if (metaTypeId != QMetaType::UnknownType) { + QMetaType metaType(metaTypeId); + if (metaType.flags() & QMetaType::PointerToQObject) { + continue; + } + } + + PropertyDef& propDef = _props.insert(idx, PropertyDef()).value(); + propDef.name = _engine->toStringHandle(QString::fromLatin1(prop.name())); + propDef.flags = QScriptValue::Undeletable | QScriptValue::PropertyGetter | QScriptValue::PropertySetter | + QScriptValue::QObjectMember; + if (prop.isConstant()) propDef.flags |= QScriptValue::ReadOnly; + } + + // discover methods + startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassMethods ? metaObject->methodCount() : 0; + num = metaObject->methodCount(); + QHash methodNames; + for (int idx = startIdx; idx < num; ++idx) { + QMetaMethod method = metaObject->method(idx); + + // perhaps keep this comment? Calls (like AudioScriptingInterface::playSound) seem to expect non-public methods to be script-accessible + /* if (method.access() != QMetaMethod::Public) continue;*/ + + bool isSignal = false; + QByteArray szName = method.name(); + + switch (method.methodType()) { + case QMetaMethod::Constructor: + continue; + case QMetaMethod::Signal: + isSignal = true; + break; + case QMetaMethod::Slot: + if (_wrapOptions & ScriptEngine::ExcludeSlots) { + continue; + } + if (szName == "deleteLater") { + continue; + } + break; + } + + QScriptString name = _engine->toStringHandle(QString::fromLatin1(szName)); + auto nameLookup = methodNames.find(name); + if (isSignal) { + if (nameLookup == methodNames.end()) { + SignalDef& signalDef = _signals.insert(idx, SignalDef()).value(); + signalDef.name = name; + signalDef.signal = method; + methodNames.insert(name, idx); + } else { + int originalMethodId = nameLookup.value(); + SignalDefMap::iterator signalLookup = _signals.find(originalMethodId); + Q_ASSERT(signalLookup != _signals.end()); + SignalDef& signalDef = signalLookup.value(); + Q_ASSERT(signalDef.signal.parameterCount() != method.parameterCount()); + if (signalDef.signal.parameterCount() < method.parameterCount()) { + signalDef.signal = method; + } + } + } else { + if (nameLookup == methodNames.end()) { + MethodDef& methodDef = _methods.insert(idx, MethodDef()).value(); + methodDef.name = name; + methodDef.methods.append(method); + methodNames.insert(name, idx); + } else { + int originalMethodId = nameLookup.value(); + MethodDefMap::iterator methodLookup = _methods.find(originalMethodId); + Q_ASSERT(methodLookup != _methods.end()); + MethodDef& methodDef = methodLookup.value(); + methodDef.methods.append(method); + } + } + } +} + +QScriptClass::QueryFlags ScriptObjectQtProxy::queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) { + // check for properties + for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) { + const PropertyDef& propDef = trans.value(); + if (propDef.name != name) continue; + *id = trans.key() | PROPERTY_TYPE; + return flags & (HandlesReadAccess | HandlesWriteAccess); + } + + // check for methods + for (MethodDefMap::const_iterator trans = _methods.cbegin(); trans != _methods.cend(); ++trans) { + if (trans.value().name != name) continue; + *id = trans.key() | METHOD_TYPE; + return flags & (HandlesReadAccess | HandlesWriteAccess); + } + + // check for signals + for (SignalDefMap::const_iterator trans = _signals.cbegin(); trans != _signals.cend(); ++trans) { + if (trans.value().name != name) continue; + *id = trans.key() | SIGNAL_TYPE; + return flags & (HandlesReadAccess | HandlesWriteAccess); + } + + return QueryFlags(); +} + +QScriptValue::PropertyFlags ScriptObjectQtProxy::propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) { + QObject* qobject = _object; + if (!qobject) { + return QScriptValue::PropertyFlags(); + } + + switch (id & TYPE_MASK) { + case PROPERTY_TYPE: { + PropertyDefMap::const_iterator lookup = _props.find(id & ~TYPE_MASK); + if (lookup == _props.cend()) return QScriptValue::PropertyFlags(); + const PropertyDef& propDef = lookup.value(); + return propDef.flags; + } + case METHOD_TYPE: { + MethodDefMap::const_iterator lookup = _methods.find(id & ~TYPE_MASK); + if (lookup == _methods.cend()) return QScriptValue::PropertyFlags(); + return QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::QObjectMember; + } + case SIGNAL_TYPE: { + SignalDefMap::const_iterator lookup = _signals.find(id & ~TYPE_MASK); + if (lookup == _signals.cend()) return QScriptValue::PropertyFlags(); + return QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::QObjectMember; + } + } + return QScriptValue::PropertyFlags(); +} + +QScriptValue ScriptObjectQtProxy::property(const QScriptValue& object, const QScriptString& name, uint id) { + QObject* qobject = _object; + if (!qobject) { + QScriptContext* currentContext = static_cast(_engine)->currentContext(); + currentContext->throwError(QScriptContext::ReferenceError, "Referencing deleted native object"); + return QScriptValue(); + } + + const QMetaObject* metaObject = qobject->metaObject(); + + switch (id & TYPE_MASK) { + case PROPERTY_TYPE: { + int propId = id & ~TYPE_MASK; + PropertyDefMap::const_iterator lookup = _props.find(propId); + if (lookup == _props.cend()) return QScriptValue(); + const PropertyDef& propDef = lookup.value(); + + QMetaProperty prop = metaObject->property(propId); + ScriptValue scriptThis = ScriptValue(new ScriptValueQtWrapper(_engine, object)); + ScriptPropertyContextQtWrapper ourContext(scriptThis, _engine->currentContext()); + ScriptContextGuard guard(&ourContext); + + QVariant varValue = prop.read(qobject); + return _engine->castVariantToValue(varValue); + } + case METHOD_TYPE: { + int methodId = id & ~TYPE_MASK; + MethodDefMap::const_iterator lookup = _methods.find(methodId); + if (lookup == _methods.cend()) return QScriptValue(); + return static_cast(_engine)->newObject( + new ScriptMethodQtProxy(_engine, qobject, object, name, lookup.value().methods)); + } + case SIGNAL_TYPE: { + int signalId = id & ~TYPE_MASK; + SignalDefMap::const_iterator defLookup = _signals.find(signalId); + if (defLookup == _signals.cend()) return QScriptValue(); + + InstanceMap::const_iterator instLookup = _signalInstances.find(signalId); + if (instLookup == _signalInstances.cend() || instLookup.value().isNull()) { + instLookup = _signalInstances.insert(signalId, + new ScriptSignalQtProxy(_engine, qobject, object, name, defLookup.value().signal)); + Q_ASSERT(instLookup != _signalInstances.cend()); + } + ScriptSignalQtProxy* proxy = instLookup.value(); + + QScriptEngine::QObjectWrapOptions options = QScriptEngine::ExcludeSuperClassContents | + QScriptEngine::ExcludeDeleteLater | + QScriptEngine::PreferExistingWrapperObject; + return static_cast(_engine)->newQObject(proxy, QScriptEngine::ScriptOwnership, options); + } + } + return QScriptValue(); +} + +void ScriptObjectQtProxy::setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) { + if (!(id & PROPERTY_TYPE)) return; + QObject* qobject = _object; + if (!qobject) { + QScriptContext* currentContext = static_cast(_engine)->currentContext(); + currentContext->throwError(QScriptContext::ReferenceError, "Referencing deleted native object"); + return; + } + + int propId = id & ~TYPE_MASK; + PropertyDefMap::const_iterator lookup = _props.find(propId); + if (lookup == _props.cend()) return; + const PropertyDef& propDef = lookup.value(); + if (propDef.flags & QScriptValue::ReadOnly) return; + + const QMetaObject* metaObject = qobject->metaObject(); + QMetaProperty prop = metaObject->property(propId); + + ScriptValue scriptThis = ScriptValue(new ScriptValueQtWrapper(_engine, object)); + ScriptPropertyContextQtWrapper ourContext(scriptThis, _engine->currentContext()); + ScriptContextGuard guard(&ourContext); + + int propTypeId = prop.userType(); + QVariant varValue; + if(!_engine->castValueToVariant(value, varValue, propTypeId)) { + QByteArray propTypeName = QMetaType(propTypeId).name(); + QByteArray valTypeName = value.toVariant().typeName(); + QScriptContext* currentContext = static_cast(_engine)->currentContext(); + currentContext->throwError(QScriptContext::TypeError, QString("Cannot convert %1 to %2").arg(valTypeName, propTypeName)); + return; + } + prop.write(qobject, varValue); +} + +ScriptVariantQtProxy::ScriptVariantQtProxy(ScriptEngineQtScript* engine, const QVariant& variant, QScriptValue scriptProto, ScriptObjectQtProxy* proto) : + QScriptClass(engine), _engine(engine), _variant(variant), _scriptProto(scriptProto), _proto(proto) { + _name = QString::fromLatin1(variant.typeName()); +} + +QScriptValue ScriptVariantQtProxy::newVariant(ScriptEngineQtScript* engine, const QVariant& variant, QScriptValue proto) { + QScriptEngine* qengine = static_cast(engine); + ScriptObjectQtProxy* protoProxy = ScriptObjectQtProxy::unwrapProxy(proto); + if (!protoProxy) { + Q_ASSERT(protoProxy); + return qengine->newVariant(variant); + } + auto proxy = QSharedPointer::create(engine, variant, proto, protoProxy); + return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); +} + +ScriptVariantQtProxy* ScriptVariantQtProxy::unwrapProxy(const QScriptValue& val) { + QScriptClass* scriptClass = val.scriptClass(); + return scriptClass ? dynamic_cast(scriptClass) : nullptr; +} + +QVariant ScriptVariantQtProxy::unwrap(const QScriptValue& val) { + ScriptVariantQtProxy* proxy = unwrapProxy(val); + return proxy ? proxy->toQtValue() : QVariant(); +} + +bool ScriptMethodQtProxy::supportsExtension(Extension extension) const { + switch (extension) { + case Callable: + return true; + default: + return false; + } +} + +QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& argument) { + if (extension != Callable) return QVariant(); + QScriptContext* context = qvariant_cast(argument); + + QObject* qobject = _object; + if (!qobject) { + context->throwError(QScriptContext::ReferenceError, "Referencing deleted native object"); + return QVariant(); + } + + int scriptNumArgs = context->argumentCount(); + Q_ASSERT(scriptNumArgs < 10); + int numArgs = std::min(scriptNumArgs, 10); + + const int scriptValueTypeId = qMetaTypeId(); + + for (auto iter = _metas.cbegin(); iter != _metas.end(); ++iter) { + const QMetaMethod& meta = *iter; + int methodNumArgs = meta.parameterCount(); + if (methodNumArgs != numArgs) { + continue; + } + + QList qScriptArgList; + QList qVarArgList; + QGenericArgument qGenArgs[10]; + int arg; + bool conversionFailed = false; + for (arg = 0; arg < numArgs && !conversionFailed; ++arg) { + int methodArgTypeId = meta.parameterType(arg); + QScriptValue argVal = context->argument(arg); + if (methodArgTypeId == scriptValueTypeId) { + qScriptArgList.append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal))); + qGenArgs[arg] = Q_ARG(ScriptValue, qScriptArgList.back()); + } else if (methodArgTypeId == QMetaType::QVariant) { + qVarArgList.append(argVal.toVariant()); + qGenArgs[arg] = Q_ARG(QVariant, qVarArgList.back()); + } else { + QVariant varArgVal; + if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) { + conversionFailed = true; + break; + /*QByteArray methodTypeName = QMetaType(methodArgTypeId).name(); + QByteArray argTypeName = argVal.toVariant().typeName(); + context->throwError(QScriptContext::TypeError, + QString("Cannot convert %1 to %2").arg(argTypeName, methodTypeName)); + return QVariant();*/ + } + qVarArgList.append(varArgVal); + const QVariant& converted = qVarArgList.back(); + + // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant + // A const_cast is needed because calling data() would detach the QVariant. + qGenArgs[arg] = + QGenericArgument(QMetaType::typeName(converted.userType()), const_cast(converted.constData())); + } + } + if (conversionFailed) { + continue; + } + + ScriptContextQtWrapper ourContext(_engine, context); + ScriptContextGuard guard(&ourContext); + + int returnTypeId = meta.returnType(); + if (returnTypeId == QMetaType::Void) { + bool success = meta.invoke(qobject, Qt::DirectConnection, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], + qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); + if (!success) { + context->throwError("Native call failed"); + } + return QVariant(); + } else if (returnTypeId == scriptValueTypeId) { + ScriptValue result; + bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0], + qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], + qGenArgs[7], qGenArgs[8], qGenArgs[9]); + if (!success) { + context->throwError("Native call failed"); + return QVariant(); + } + QScriptValue qResult = ScriptValueQtWrapper::fullUnwrap(_engine, result); + return QVariant::fromValue(qResult); + } else { + // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant + const char* typeName = meta.typeName(); + QVariant qRetVal(returnTypeId, static_cast(NULL)); + QGenericReturnArgument sRetVal(typeName, const_cast(qRetVal.constData())); + + bool success = + meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], + qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); + if (!success) { + context->throwError("Native call failed"); + return QVariant(); + } + QScriptValue qResult = _engine->castVariantToValue(qRetVal); + return QVariant::fromValue(qResult); + } + } + context->throwError("Native call failed: could not locate an overload with the requested arguments"); + return QVariant(); +} + +// Adapted from https://doc.qt.io/archives/qq/qq16-dynamicqobject.html, for connecting to a signal without a compile-time definition for it +int ScriptSignalQtProxy::qt_metacall(QMetaObject::Call call, int id, void** arguments) { + id = ScriptSignalQtProxyBase::qt_metacall(call, id, arguments); + if (id != 0 || call != QMetaObject::InvokeMetaMethod) { + return id; + } + + QScriptValueList args; + int numArgs = _meta.parameterCount(); + for (int arg = 0; arg < numArgs; ++arg) { + int methodArgTypeId = _meta.parameterType(arg); + QVariant argValue(methodArgTypeId, arguments[arg+1]); + args.append(_engine->castVariantToValue(argValue)); + } + + for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) { + Connection& conn = *iter; + conn.callback.call(conn.thisValue, args); + } + + return -1; +} + +int ScriptSignalQtProxy::discoverMetaCallIdx() { + const QMetaObject* ourMeta = metaObject(); + return ourMeta->methodCount(); +} + +ScriptSignalQtProxy::ConnectionList::iterator ScriptSignalQtProxy::findConnection(QScriptValue thisObject, + QScriptValue callback) { + for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) { + Connection& conn = *iter; + if (conn.callback.strictlyEquals(callback) && conn.thisValue.strictlyEquals(thisObject)) { + return iter; + } + } + return _connections.end(); +} + + +void ScriptSignalQtProxy::connect(QScriptValue arg0, QScriptValue arg1) { + QObject* qobject = _object; + if (!qobject) { + QScriptContext* currentContext = static_cast(_engine)->currentContext(); + currentContext->throwError(QScriptContext::ReferenceError, "Referencing deleted native object"); + return; + } + + // untangle the arguments + QScriptValue callback; + QScriptValue callbackThis; + if (arg1.isFunction()) { + callbackThis = arg0; + callback = arg1; + } else { + callback = arg0; + } + if (!callback.isFunction()) { + QScriptContext* currentContext = static_cast(_engine)->currentContext(); + currentContext->throwError(QScriptContext::TypeError, "Function expected as argument to 'connect'"); + return; + } + + // are we already connected? + ConnectionList::iterator lookup = findConnection(callbackThis, callback); + if (lookup != _connections.end()) { + return; // already exists + } + + // add a reference to ourselves to the destination callback + QScriptValue destData = callback.data(); + Q_ASSERT(!destData.isValid() || destData.isArray()); + if (!destData.isArray()) { + destData = static_cast(_engine)->newArray(); + } + { + QScriptValueList args; + args << thisObject(); + destData.property("push").call(destData, args); + } + callback.setData(destData); + + // add this to our internal list of connections + Connection newConn; + newConn.callback = callback; + newConn.thisValue = callbackThis; + _connections.append(newConn); + + // inform Qt that we're connecting to this signal + if (!_isConnected) { + auto result = QMetaObject::connect(qobject, _meta.methodIndex(), this, _metaCallId); + Q_ASSERT(result); + _isConnected = true; + } +} + +void ScriptSignalQtProxy::disconnect(QScriptValue arg0, QScriptValue arg1) { + QObject* qobject = _object; + if (!qobject) { + QScriptContext* currentContext = static_cast(_engine)->currentContext(); + currentContext->throwError(QScriptContext::ReferenceError, "Referencing deleted native object"); + return; + } + + // untangle the arguments + QScriptValue callback; + QScriptValue callbackThis; + if (arg1.isFunction()) { + callbackThis = arg0; + callback = arg1; + } else { + callback = arg0; + } + if (!callback.isFunction()) { + QScriptContext* currentContext = static_cast(_engine)->currentContext(); + currentContext->throwError(QScriptContext::TypeError, "Function expected as argument to 'disconnect'"); + return; + } + + // locate this connection in our list of connections + ConnectionList::iterator lookup = findConnection(callbackThis, callback); + if (lookup == _connections.end()) { + return; // not here + } + + // remove it from our internal list of connections + _connections.erase(lookup); + + // remove a reference to ourselves from the destination callback + QScriptValue destData = callback.data(); + Q_ASSERT(destData.isArray()); + if (destData.isArray()) { + QScriptValue qThis = thisObject(); + int len = destData.property("length").toInteger(); + bool foundIt = false; + for (int idx = 0; idx < len && !foundIt; ++idx) { + QScriptValue entry = destData.property(idx); + if (entry.strictlyEquals(qThis)) { + foundIt = true; + QScriptValueList args; + args << idx << 1; + destData.property("splice").call(destData, args); + } + } + Q_ASSERT(foundIt); + } + + // inform Qt that we're no longer connected to this signal + if (_connections.empty()) { + Q_ASSERT(_isConnected); + bool result = QMetaObject::disconnect(qobject, _meta.methodIndex(), this, _metaCallId); + Q_ASSERT(result); + _isConnected = false; + } +} diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h new file mode 100644 index 00000000000..efd9070bb36 --- /dev/null +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h @@ -0,0 +1,205 @@ +// +// ScriptObjectQtProxy.h +// libraries/script-engine/src/qtscript +// +// Created by Heather Anderson on 12/5/21. +// Copyright 2021 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +/// @addtogroup ScriptEngine +/// @{ + +#ifndef hifi_ScriptObjectQtProxy_h +#define hifi_ScriptObjectQtProxy_h + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../ScriptEngine.h" +#include "ScriptEngineQtScript.h" + +class ScriptEngineQtScript; +class ScriptSignalQtProxy; + +/// [QtScript] (re-)implements the translation layer between ScriptValue and QObject. This object +/// will focus exclusively on property get/set until function calls appear to be a problem +class ScriptObjectQtProxy final : public QScriptClass { +private: // implementation + struct PropertyDef { + QScriptString name; + QScriptValue::PropertyFlags flags; + }; + struct MethodDef { + QScriptString name; + QList methods; + }; + struct SignalDef { + QScriptString name; + QMetaMethod signal; + }; + using PropertyDefMap = QHash; + using MethodDefMap = QHash; + using SignalDefMap = QHash; + using InstanceMap = QHash >; + + static constexpr uint PROPERTY_TYPE = 0x1000; + static constexpr uint METHOD_TYPE = 0x2000; + static constexpr uint SIGNAL_TYPE = 0x3000; + static constexpr uint TYPE_MASK = 0xF000; + +public: // construction + inline ScriptObjectQtProxy(ScriptEngineQtScript* engine, QObject* object, bool ownsObject, const ScriptEngine::QObjectWrapOptions& options) : + QScriptClass(engine), _engine(engine), _object(object), _wrapOptions(options), _ownsObject(ownsObject) { + investigate(); + } + virtual ~ScriptObjectQtProxy(); + + static QScriptValue newQObject(ScriptEngineQtScript* engine, + QObject* object, + ScriptEngine::ValueOwnership ownership = ScriptEngine::QtOwnership, + const ScriptEngine::QObjectWrapOptions& options = ScriptEngine::QObjectWrapOptions()); + static ScriptObjectQtProxy* unwrapProxy(const QScriptValue& val); + static QObject* unwrap(const QScriptValue& val); + inline QObject* toQtValue() const { return _object; } + +public: // QScriptClass implementation + virtual QString name() const override { return _name; } + + virtual QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; + virtual QScriptValue::PropertyFlags propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) override; + virtual QueryFlags queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) override; + virtual void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override; + +private: // implementation + void investigate(); + +private: // storage + ScriptEngineQtScript* _engine; + const ScriptEngine::QObjectWrapOptions _wrapOptions; + PropertyDefMap _props; + MethodDefMap _methods; + SignalDefMap _signals; + InstanceMap _signalInstances; + const bool _ownsObject; + QPointer _object; + QString _name; + + Q_DISABLE_COPY(ScriptObjectQtProxy) +}; + +/// [QtScript] (re-)implements the translation layer between ScriptValue and QVariant where a prototype is set. +/// This object depends on a ScriptObjectQtProxy to provide the prototype's behavior +class ScriptVariantQtProxy final : public QScriptClass { +public: // construction + ScriptVariantQtProxy(ScriptEngineQtScript* engine, const QVariant& variant, QScriptValue scriptProto, ScriptObjectQtProxy* proto); + + static QScriptValue newVariant(ScriptEngineQtScript* engine, const QVariant& variant, QScriptValue proto); + static ScriptVariantQtProxy* unwrapProxy(const QScriptValue& val); + static QVariant unwrap(const QScriptValue& val); + inline QVariant toQtValue() const { return _variant; } + +public: // QScriptClass implementation + virtual QString name() const override { return _name; } + + virtual QScriptValue prototype() const override { return _scriptProto; } + + virtual QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override { + return _proto->property(object, name, id); + } + virtual QScriptValue::PropertyFlags propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) override { + return _proto->propertyFlags(object, name, id); + } + virtual QueryFlags queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) override { + return _proto->queryProperty(object, name, flags, id); + } + virtual void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override { + return _proto->setProperty(object, name, id, value); + } + +private: // storage + ScriptEngineQtScript* _engine; + QVariant _variant; + QScriptValue _scriptProto; + ScriptObjectQtProxy* _proto; + QString _name; + + Q_DISABLE_COPY(ScriptVariantQtProxy) +}; + +class ScriptMethodQtProxy final : public QScriptClass { +public: // construction + inline ScriptMethodQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, QString name, const QList& metas) : + QScriptClass(engine), _engine(engine), _object(object), _objectLifetime(lifetime), _name(name), _metas(metas) {} + +public: // QScriptClass implementation + virtual QString name() const override { return _name; } + virtual bool supportsExtension(Extension extension) const override; + virtual QVariant extension(Extension extension, const QVariant& argument = QVariant()) override; + +private: // storage + ScriptEngineQtScript* _engine; + QPointer _object; + QScriptValue _objectLifetime; + const QString _name; + const QList _metas; + + Q_DISABLE_COPY(ScriptMethodQtProxy) +}; + +// This abstract base class serves solely to declare the Q_INVOKABLE methods for ScriptSignalQtProxy +// as we're overriding qt_metacall later for the signal callback yet still want to support +// metacalls for the connect/disconnect API +class ScriptSignalQtProxyBase : public QObject, protected QScriptable { + Q_OBJECT +public: // API + Q_INVOKABLE virtual void connect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) = 0; + Q_INVOKABLE virtual void disconnect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) = 0; +}; + +class ScriptSignalQtProxy final : public ScriptSignalQtProxyBase { +private: // storage + struct Connection { + QScriptValue thisValue; + QScriptValue callback; + }; + using ConnectionList = QList; + +public: // construction + inline ScriptSignalQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, QString name, const QMetaMethod& meta) : + _engine(engine), _object(object), _objectLifetime(lifetime), _name(name), _meta(meta), _metaCallId(discoverMetaCallIdx()) {} + +private: // implementation + virtual int qt_metacall(QMetaObject::Call call, int id, void** arguments); + int discoverMetaCallIdx(); + ConnectionList::iterator findConnection(QScriptValue thisObject, QScriptValue callback); + +public: // API + virtual void connect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) override; + virtual void disconnect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) override; + +private: // storage + ScriptEngineQtScript* _engine; + QPointer _object; + QScriptValue _objectLifetime; + QString _name; + const QMetaMethod _meta; + const int _metaCallId; + ConnectionList _connections; + bool _isConnected{ false }; + + Q_DISABLE_COPY(ScriptSignalQtProxy) +}; + +#endif // hifi_ScriptObjectQtProxy_h + +/// @} diff --git a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp index 4eb32476ea0..cae3de30f89 100644 --- a/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptValueQtWrapper.cpp @@ -28,19 +28,27 @@ ScriptValueQtWrapper* ScriptValueQtWrapper::unwrap(const ScriptValue& val) { QScriptValue ScriptValueQtWrapper::fullUnwrap(const ScriptValue& value) const { ScriptValueQtWrapper* unwrapped = unwrap(value); if (unwrapped) { - return unwrapped->toQtValue(); + if (unwrapped->engine().get() != _engine) { + return static_cast(_engine)->toScriptValue(unwrapped->toVariant()); + } else { + return unwrapped->toQtValue(); + } } QVariant varValue = value.toVariant(); - return static_cast(_engine)->newVariant(varValue); + return _engine->castVariantToValue(varValue); } QScriptValue ScriptValueQtWrapper::fullUnwrap(ScriptEngineQtScript* engine, const ScriptValue& value) { ScriptValueQtWrapper* unwrapped = unwrap(value); if (unwrapped) { - return unwrapped->toQtValue(); + if (unwrapped->engine().get() != engine) { + return static_cast(engine)->toScriptValue(unwrapped->toVariant()); + } else { + return unwrapped->toQtValue(); + } } QVariant varValue = value.toVariant(); - return static_cast(engine)->newVariant(varValue); + return engine->castVariantToValue(varValue); } ScriptValue ScriptValueQtWrapper::call(const ScriptValue& thisObject, const ScriptValueList& args) { @@ -157,11 +165,23 @@ quint32 ScriptValueQtWrapper::toUInt32() const { } QVariant ScriptValueQtWrapper::toVariant() const { - return _value.toVariant(); + QVariant dest; + if (_engine->castValueToVariant(_value, dest, QMetaType::UnknownType)) { + return dest; + } else { + Q_ASSERT(false); + return QVariant(); + } } QObject* ScriptValueQtWrapper::toQObject() const { - return _value.toQObject(); + QVariant dest; + if (_engine->castValueToVariant(_value, dest, QMetaType::QObjectStar)) { + return dest.value(); + } else { + Q_ASSERT(false); + return nullptr; + } } bool ScriptValueQtWrapper::equals(const ScriptValue& other) const { diff --git a/libraries/ui/src/ui/QmlWrapper.h b/libraries/ui/src/ui/QmlWrapper.h index 8e110ffee3c..42091d55490 100644 --- a/libraries/ui/src/ui/QmlWrapper.h +++ b/libraries/ui/src/ui/QmlWrapper.h @@ -40,8 +40,9 @@ ScriptValue wrapperToScriptValue(ScriptEngine* engine, T* const &in) { } template -void wrapperFromScriptValue(const ScriptValue& value, T* &out) { +bool wrapperFromScriptValue(const ScriptValue& value, T* &out) { out = qobject_cast(value.toQObject()); + return !!out; } #endif \ No newline at end of file From 3035457e3c848d80597f07e63cc24640011d3f3e Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Tue, 14 Dec 2021 19:55:13 -0800 Subject: [PATCH 25/34] not sure what would have broken this but... adding required windows dependencies for MIDI to operate --- libraries/midi/CMakeLists.txt | 4 ++++ libraries/midi/src/Midi.cpp | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/midi/CMakeLists.txt b/libraries/midi/CMakeLists.txt index a698dfc9bbc..66757566408 100644 --- a/libraries/midi/CMakeLists.txt +++ b/libraries/midi/CMakeLists.txt @@ -2,3 +2,7 @@ set(TARGET_NAME midi) setup_hifi_library(Network) link_hifi_libraries(shared networking) include_hifi_library_headers(script-engine) + +if (WIN32) + target_link_libraries(${TARGET_NAME} winmm.lib) +endif () diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index d88f31394e7..8544a809810 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -19,10 +19,9 @@ #include #if defined Q_OS_WIN32 -#include "Windows.h" -#endif +#include +#include -#if defined Q_OS_WIN32 const int MIDI_BYTE_MASK = 0x0FF; const int MIDI_NIBBLE_MASK = 0x00F; const int MIDI_PITCH_BEND_MASK = 0x3F80; From 0144609665467c7e57f38ca2af30cdc036e6148e Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Tue, 14 Dec 2021 19:57:50 -0800 Subject: [PATCH 26/34] Continued tightening and testing of the scripting engine "glue" logic - QObject wrappers will now be reused when asked to wrap the same QObject multiple times - improved error reporting when we can't form a native call from script - dropped support for having the existing QtScript logic handle Qt object transformations - assuming that our code will handle all calls into native objects - changing timer functions to use CTimer* publicly rather than casted QObject* --- libraries/audio/src/AudioEffectOptions.cpp | 2 +- libraries/script-engine/src/ScriptManager.cpp | 9 +- libraries/script-engine/src/ScriptManager.h | 13 +- .../src/qtscript/ArrayBufferClass.cpp | 3 - .../src/qtscript/ScriptContextQtAgent.cpp | 73 ----- .../src/qtscript/ScriptContextQtAgent.h | 48 --- .../src/qtscript/ScriptEngineQtScript.cpp | 21 +- .../src/qtscript/ScriptEngineQtScript.h | 19 +- .../qtscript/ScriptEngineQtScript_cast.cpp | 275 ++++++------------ .../src/qtscript/ScriptObjectQtProxy.cpp | 162 +++++++++-- .../src/qtscript/ScriptObjectQtProxy.h | 19 +- 11 files changed, 262 insertions(+), 382 deletions(-) delete mode 100644 libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp delete mode 100644 libraries/script-engine/src/qtscript/ScriptContextQtAgent.h diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 2c9c9462021..bed083d7dbd 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -150,5 +150,5 @@ AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &othe } ScriptValue AudioEffectOptions::constructor(ScriptContext* context, ScriptEngine* engine) { - return engine->newQObject(new AudioEffectOptions(context->argument(0))); + return engine->newQObject(new AudioEffectOptions(context->argument(0)), ScriptEngine::ScriptOwnership); } diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 3d18b59197e..81d99521415 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -79,9 +79,6 @@ static const ScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS{ READONLY_PRO static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; -Q_DECLARE_METATYPE(ScriptEngine::FunctionSignature) -int functionSignatureMetaID = qRegisterMetaType(); - int scriptManagerPointerMetaID = qRegisterMetaType(); Q_DECLARE_METATYPE(ExternalResource::Bucket); @@ -1054,7 +1051,7 @@ void ScriptManager::timerFired() { } } -QObject* ScriptManager::setupTimerWithInterval(const ScriptValue& function, int intervalMS, bool isSingleShot) { +QTimer* ScriptManager::setupTimerWithInterval(const ScriptValue& function, int intervalMS, bool isSingleShot) { // create the timer, add it to the map, and start it QTimer* newTimer = new QTimer(this); newTimer->setSingleShot(isSingleShot); @@ -1078,7 +1075,7 @@ QObject* ScriptManager::setupTimerWithInterval(const ScriptValue& function, int return newTimer; } -QObject* ScriptManager::setInterval(const ScriptValue& function, int intervalMS) { +QTimer* ScriptManager::setInterval(const ScriptValue& function, int intervalMS) { if (isStopped()) { scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename()); return NULL; // bail early @@ -1087,7 +1084,7 @@ QObject* ScriptManager::setInterval(const ScriptValue& function, int intervalMS) return setupTimerWithInterval(function, intervalMS, false); } -QObject* ScriptManager::setTimeout(const ScriptValue& function, int timeoutMS) { +QTimer* ScriptManager::setTimeout(const ScriptValue& function, int timeoutMS) { if (isStopped()) { scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename()); return NULL; // bail early diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index 8a13ea012ed..ae9571cb026 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,8 @@ using ScriptValueList = QList; Q_DECLARE_METATYPE(ScriptManagerPointer) +const int QTREGISTER_QTimerStar = qRegisterMetaType(); + class CallbackData { public: ScriptValue function; @@ -433,7 +436,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * print("Interval timer fired"); * }, 1000); */ - Q_INVOKABLE QObject* setInterval(const ScriptValue& function, int intervalMS); + Q_INVOKABLE QTimer* setInterval(const ScriptValue& function, int intervalMS); /*@jsdoc * Calls a function once, after a delay. @@ -446,7 +449,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * print("Timeout timer fired"); * }, 1000); */ - Q_INVOKABLE QObject* setTimeout(const ScriptValue& function, int timeoutMS); + Q_INVOKABLE QTimer* setTimeout(const ScriptValue& function, int timeoutMS); /*@jsdoc * Stops an interval timer set by {@link Script.setInterval|setInterval}. @@ -464,7 +467,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * Script.clearInterval(timer); * }, 10000); */ - Q_INVOKABLE void clearInterval(QObject* timer) { stopTimer(reinterpret_cast(timer)); } + Q_INVOKABLE void clearInterval(QTimer* timer) { stopTimer(timer); } /*@jsdoc * Stops a timeout timer set by {@link Script.setTimeout|setTimeout}. @@ -479,7 +482,7 @@ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, publi * // Uncomment the following line to stop the timer from firing. * //Script.clearTimeout(timer); */ - Q_INVOKABLE void clearTimeout(QObject* timer) { stopTimer(reinterpret_cast(timer)); } + Q_INVOKABLE void clearTimeout(QTimer* timer) { stopTimer(timer); } /*@jsdoc * Prints a message to the program log and emits {@link Script.printedMessage}. @@ -905,7 +908,7 @@ public slots: void setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details); void setParentURL(const QString& parentURL) { _parentURL = parentURL; } - QObject* setupTimerWithInterval(const ScriptValue& function, int intervalMS, bool isSingleShot); + QTimer* setupTimerWithInterval(const ScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); QHash _registeredHandlers; diff --git a/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp b/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp index 85564bc114b..e5ae13e7d41 100644 --- a/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp +++ b/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp @@ -23,10 +23,7 @@ static const QString CLASS_NAME = "ArrayBuffer"; // FIXME: Q_DECLARE_METATYPE is global and really belongs in a shared header file, not per .cpp like this // (see DataViewClass.cpp, etc. which would also have to be updated to resolve) -Q_DECLARE_METATYPE(QScriptClass*) Q_DECLARE_METATYPE(QByteArray*) -int qScriptClassPointerMetaTypeId = qRegisterMetaType(); -int qByteArrayPointerMetaTypeId = qRegisterMetaType(); ArrayBufferClass::ArrayBufferClass(ScriptEngineQtScript* scriptEngine) : QObject(scriptEngine), diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp deleted file mode 100644 index e082272a630..00000000000 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// ScriptContextQtAgent.cpp -// libraries/script-engine/src/qtscript -// -// Created by Heather Anderson on 5/22/21. -// Copyright 2021 Vircadia contributors. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "ScriptContextQtAgent.h" - -#include - -#include "../Scriptable.h" -#include "ScriptContextQtWrapper.h" -#include "ScriptEngineQtScript.h" - -void ScriptContextQtAgent::contextPop() { - if (_prevAgent) { - _prevAgent->contextPop(); - } - if (_engine->currentContext() == _currContext.get()) { - _currContext.reset(); - if (!_contextActive && !_contextStack.empty()) { - _currContext = _contextStack.back(); - _contextStack.pop_back(); - _contextActive = true; - } - } -} - -void ScriptContextQtAgent::contextPush() { - if (_prevAgent) { - _prevAgent->contextPush(); - } - if (_contextActive && _currContext) { - _contextStack.push_back(_currContext); - _contextActive = false; - } - _currContext.reset(); -} - -void ScriptContextQtAgent::functionEntry(qint64 scriptId) { - if (_prevAgent) { - _prevAgent->functionEntry(scriptId); - } - if (scriptId != -1) { - return; - } - if (!_currContext) { - _currContext = std::make_shared(_engine, static_cast(_engine)->currentContext()); - } - Scriptable::setContext(_currContext.get()); - _contextActive = true; -} - -void ScriptContextQtAgent::functionExit(qint64 scriptId, const QScriptValue& returnValue) { - if (_prevAgent) { - _prevAgent->functionExit(scriptId, returnValue); - } - if (scriptId != -1) { - return; - } - _contextActive = false; - if (!_contextActive && !_contextStack.empty()) { - _currContext = _contextStack.back(); - _contextStack.pop_back(); - Scriptable::setContext(_currContext.get()); - _contextActive = true; - } -} diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h b/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h deleted file mode 100644 index 0869e5a50ff..00000000000 --- a/libraries/script-engine/src/qtscript/ScriptContextQtAgent.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// ScriptContextQtAgent.h -// libraries/script-engine/src/qtscript -// -// Created by Heather Anderson on 5/22/21. -// Copyright 2021 Vircadia contributors. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_ScriptContextQtAgent_h -#define hifi_ScriptContextQtAgent_h - -#include - -#include -#include - -#include "ScriptEngineQtScript.h" - -class QScriptContext; -class QScriptValue; -class ScriptContextQtWrapper; -class ScriptEngineQtScript; -using ScriptContextQtPointer = std::shared_ptr; - -class ScriptContextQtAgent final : public QScriptEngineAgent { -public: // construction - inline ScriptContextQtAgent(ScriptEngineQtScript* engine, QScriptEngineAgent* prevAgent) : - QScriptEngineAgent(engine), _engine(engine), _prevAgent(prevAgent) {} - virtual ~ScriptContextQtAgent() {} - -public: // QScriptEngineAgent implementation - virtual void contextPop() override; - virtual void contextPush() override; - virtual void functionEntry(qint64 scriptId) override; - virtual void functionExit(qint64 scriptId, const QScriptValue& returnValue) override; - -private: // storage - bool _contextActive{ false }; - QList _contextStack; - ScriptContextQtPointer _currContext; - ScriptEngineQtScript* _engine; - QScriptEngineAgent* _prevAgent; -}; - -#endif // hifi_ScriptContextQtAgent_h \ No newline at end of file diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index e5ce15898bf..7b4a39f9428 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -52,15 +52,9 @@ #include "ScriptObjectQtProxy.h" #include "ScriptProgramQtWrapper.h" #include "ScriptValueQtWrapper.h" -#include "ScriptContextQtAgent.h" static const int MAX_DEBUG_VALUE_LENGTH { 80 }; -Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) -int qfunctionSignatureMetaID = qRegisterMetaType(); - -int scriptEnginePointerMetaID = qRegisterMetaType(); - bool ScriptEngineQtScript::IS_THREADSAFE_INVOCATION(const QThread* thread, const QString& method) { const QThread* currentThread = QThread::currentThread(); if (currentThread == thread) { @@ -336,13 +330,6 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : _undefinedValue = ScriptValue(new ScriptValueQtWrapper(this, std::move(undefined))); QScriptEngine::setProcessEventsInterval(MSECS_PER_SECOND); - - _contextAgent = new ScriptContextQtAgent(this, agent()); - setAgent(_contextAgent); -} - -ScriptEngineQtScript::~ScriptEngineQtScript() { - delete _contextAgent; } void ScriptEngineQtScript::registerEnum(const QString& enumName, QMetaEnum newEnum) { @@ -912,20 +899,20 @@ ScriptValue ScriptEngineQtScript::create(int type, const void* ptr) { return ScriptValue(new ScriptValueQtWrapper(this, std::move(scriptValue))); } -QVariant ScriptEngineQtScript::convert(const ScriptValue& value, int type) { +QVariant ScriptEngineQtScript::convert(const ScriptValue& value, int typeId) { ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); if (unwrapped == nullptr) { return QVariant(); } QVariant var; - if (!castValueToVariant(unwrapped->toQtValue(), var, type)) { + if (!castValueToVariant(unwrapped->toQtValue(), var, typeId)) { return QVariant(); } int destType = var.userType(); - if (destType != type) { - var.convert(type); // if conversion fails then var is set to QVariant() + if (destType != typeId) { + var.convert(typeId); // if conversion fails then var is set to QVariant() } return var; diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 5dd685292f2..dcc87207c80 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -34,13 +35,12 @@ #include "ArrayBufferClass.h" class ScriptContextQtWrapper; -class ScriptContextQtAgent; class ScriptEngineQtScript; class ScriptManager; -using ScriptEngineQtScriptPointer = std::shared_ptr; +class ScriptObjectQtProxy; using ScriptContextQtPointer = std::shared_ptr; -Q_DECLARE_METATYPE(ScriptEngineQtScriptPointer); +Q_DECLARE_METATYPE(ScriptEngine::FunctionSignature) /// [QtScript] Implements ScriptEngine for QtScript and translates calls for QScriptEngine class ScriptEngineQtScript final : public QScriptEngine, @@ -50,7 +50,6 @@ class ScriptEngineQtScript final : public QScriptEngine, public: // construction ScriptEngineQtScript(ScriptManager* scriptManager = nullptr); - ~ScriptEngineQtScript(); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can @@ -150,11 +149,16 @@ class ScriptEngineQtScript final : public QScriptEngine, public: // not for public use, but I don't like how Qt strings this along with private friend functions virtual ScriptValue create(int type, const void* ptr) override; - virtual QVariant convert(const ScriptValue& value, int type) override; + virtual QVariant convert(const ScriptValue& value, int typeId) override; virtual void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, ScriptEngine::DemarshalFunction demarshalFunc) override; - bool castValueToVariant(const QScriptValue& val, QVariant& dest, int destType); + bool castValueToVariant(const QScriptValue& val, QVariant& dest, int destTypeId); QScriptValue castVariantToValue(const QVariant& val); + static QString valueType(const QScriptValue& val); + + using ObjectWrapperMap = QMap>; + mutable QMutex _qobjectWrapperMapProtect; + ObjectWrapperMap _qobjectWrapperMap; protected: // like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues @@ -180,14 +184,11 @@ class ScriptEngineQtScript final : public QScriptEngine, mutable QMutex _customTypeProtect; CustomMarshalMap _customTypes; CustomPrototypeMap _customPrototypes; - int _nextCustomType = 0; ScriptValue _nullValue; ScriptValue _undefinedValue; mutable ScriptContextQtPointer _currContext; ArrayBufferClass* _arrayBufferClass; - - ScriptContextQtAgent* _contextAgent{ nullptr }; }; // Lambda helps create callable QScriptValues out of std::functions: diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript_cast.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript_cast.cpp index 69125ec6070..7b799d168fd 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript_cast.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript_cast.cpp @@ -16,64 +16,16 @@ #include #include +#include "../ScriptEngineCast.h" #include "../ScriptValueIterator.h" #include "ScriptObjectQtProxy.h" #include "ScriptValueQtWrapper.h" -template -class CustomTypeInstance { -public: - static ScriptEngine::MarshalFunction marshalFunc; - static ScriptEngine::DemarshalFunction demarshalFunc; - - static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) { - ScriptEngineQtScript* unwrappedEngine = static_cast(engine); - ScriptValue dest = marshalFunc(unwrappedEngine, src); - return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest); - } - - static void internalDemarshalFunc(const QScriptValue& src, void* dest) { - ScriptEngineQtScript* unwrappedEngine = static_cast(src.engine()); - ScriptValue wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src)); - demarshalFunc(wrappedSrc, dest); - } -}; -template -ScriptEngine::MarshalFunction CustomTypeInstance::marshalFunc; -template -ScriptEngine::DemarshalFunction CustomTypeInstance::demarshalFunc; - -// I would *LOVE* it if there was a different way to do this, jeez! -// Qt requires two functions that have no parameters that give any context, -// one of the must return a QScriptValue (so we can't void* them into generics and stick them in the templates). -// This *has* to be done via templates but the whole point of this is to avoid leaking types into the rest of -// the system that would require anyone other than us to have a dependency on QtScript -#define CUSTOM_TYPE_ENTRY(idx) \ - case idx: \ - CustomTypeInstance::marshalFunc = marshalFunc; \ - CustomTypeInstance::demarshalFunc = demarshalFunc; \ - internalMarshalFunc = CustomTypeInstance::internalMarshalFunc; \ - internalDemarshalFunc = CustomTypeInstance::internalDemarshalFunc; \ - break; -#define CUSTOM_TYPE_ENTRY_10(idx) \ - CUSTOM_TYPE_ENTRY((idx * 10)); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 1); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 2); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 3); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 4); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 5); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 6); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 7); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 8); \ - CUSTOM_TYPE_ENTRY((idx * 10) + 9); - void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) { ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype); if (unwrappedPrototype) { const QScriptValue& scriptPrototype = unwrappedPrototype->toQtValue(); - QScriptEngine::setDefaultPrototype(metaTypeId, scriptPrototype); - QMutexLocker guard(&_customTypeProtect); _customPrototypes.insert(metaTypeId, scriptPrototype); } @@ -83,59 +35,12 @@ void ScriptEngineQtScript::registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, ScriptEngine::DemarshalFunction demarshalFunc) { - QScriptEngine::MarshalFunction internalMarshalFunc; - QScriptEngine::DemarshalFunction internalDemarshalFunc; - - { - QMutexLocker guard(&_customTypeProtect); - - // storing it in a map for our own benefit - CustomMarshal& customType = _customTypes.insert(type, CustomMarshal()).value(); - customType.demarshalFunc = demarshalFunc; - customType.marshalFunc = marshalFunc; - - // creating a conversion for QtScript's benefit - if (_nextCustomType >= 300) { // have we ran out of translators? - Q_ASSERT(false); - return; - } - - switch (_nextCustomType++) { - CUSTOM_TYPE_ENTRY_10(0); - CUSTOM_TYPE_ENTRY_10(1); - CUSTOM_TYPE_ENTRY_10(2); - CUSTOM_TYPE_ENTRY_10(3); - CUSTOM_TYPE_ENTRY_10(4); - CUSTOM_TYPE_ENTRY_10(5); - CUSTOM_TYPE_ENTRY_10(6); - CUSTOM_TYPE_ENTRY_10(7); - CUSTOM_TYPE_ENTRY_10(8); - CUSTOM_TYPE_ENTRY_10(9); - CUSTOM_TYPE_ENTRY_10(10); - CUSTOM_TYPE_ENTRY_10(11); - CUSTOM_TYPE_ENTRY_10(12); - CUSTOM_TYPE_ENTRY_10(13); - CUSTOM_TYPE_ENTRY_10(14); - CUSTOM_TYPE_ENTRY_10(15); - CUSTOM_TYPE_ENTRY_10(16); - CUSTOM_TYPE_ENTRY_10(17); - CUSTOM_TYPE_ENTRY_10(18); - CUSTOM_TYPE_ENTRY_10(19); - CUSTOM_TYPE_ENTRY_10(20); - CUSTOM_TYPE_ENTRY_10(21); - CUSTOM_TYPE_ENTRY_10(22); - CUSTOM_TYPE_ENTRY_10(23); - CUSTOM_TYPE_ENTRY_10(24); - CUSTOM_TYPE_ENTRY_10(25); - CUSTOM_TYPE_ENTRY_10(26); - CUSTOM_TYPE_ENTRY_10(27); - CUSTOM_TYPE_ENTRY_10(28); - CUSTOM_TYPE_ENTRY_10(29); - CUSTOM_TYPE_ENTRY_10(30); - } - } + QMutexLocker guard(&_customTypeProtect); - qScriptRegisterMetaType_helper(this, type, internalMarshalFunc, internalDemarshalFunc, QScriptValue()); + // storing it in a map for our own benefit + CustomMarshal& customType = _customTypes.insert(type, CustomMarshal()).value(); + customType.demarshalFunc = demarshalFunc; + customType.marshalFunc = marshalFunc; } Q_DECLARE_METATYPE(ScriptValue); @@ -149,8 +54,7 @@ static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValue& de dest = ScriptValue(new ScriptValueQtWrapper(engine, src)); } -static ScriptValue StringListToScriptValue(ScriptEngine* engine, const void* pSrc) { - const QStringList& src = *reinterpret_cast(pSrc); +static ScriptValue StringListToScriptValue(ScriptEngine* engine, const QStringList& src) { int len = src.length(); ScriptValue dest = engine->newArray(len); for (int idx = 0; idx < len; ++idx) { @@ -159,9 +63,8 @@ static ScriptValue StringListToScriptValue(ScriptEngine* engine, const void* pSr return dest; } -static bool StringListFromScriptValue(const ScriptValue& src, void* pDest) { +static bool StringListFromScriptValue(const ScriptValue& src, QStringList& dest) { if(!src.isArray()) return false; - QStringList& dest = *reinterpret_cast(pDest); int len = src.property("length").toInteger(); dest.clear(); for (int idx = 0; idx < len; ++idx) { @@ -170,8 +73,7 @@ static bool StringListFromScriptValue(const ScriptValue& src, void* pDest) { return true; } -static ScriptValue VariantListToScriptValue(ScriptEngine* engine, const void* pSrc) { - const QVariantList& src = *reinterpret_cast(pSrc); +static ScriptValue VariantListToScriptValue(ScriptEngine* engine, const QVariantList& src) { int len = src.length(); ScriptValue dest = engine->newArray(len); for (int idx = 0; idx < len; ++idx) { @@ -180,9 +82,8 @@ static ScriptValue VariantListToScriptValue(ScriptEngine* engine, const void* pS return dest; } -static bool VariantListFromScriptValue(const ScriptValue& src, void* pDest) { +static bool VariantListFromScriptValue(const ScriptValue& src, QVariantList& dest) { if(!src.isArray()) return false; - QVariantList& dest = *reinterpret_cast(pDest); int len = src.property("length").toInteger(); dest.clear(); for (int idx = 0; idx < len; ++idx) { @@ -191,8 +92,7 @@ static bool VariantListFromScriptValue(const ScriptValue& src, void* pDest) { return true; } -static ScriptValue VariantMapToScriptValue(ScriptEngine* engine, const void* pSrc) { - const QVariantMap& src = *reinterpret_cast(pSrc); +static ScriptValue VariantMapToScriptValue(ScriptEngine* engine, const QVariantMap& src) { ScriptValue dest = engine->newObject(); for (QVariantMap::const_iterator iter = src.cbegin(); iter != src.cend(); ++iter) { dest.setProperty(iter.key(), engine->newVariant(iter.value())); @@ -200,8 +100,7 @@ static ScriptValue VariantMapToScriptValue(ScriptEngine* engine, const void* pSr return dest; } -static bool VariantMapFromScriptValue(const ScriptValue& src, void* pDest) { - QVariantMap& dest = *reinterpret_cast(pDest); +static bool VariantMapFromScriptValue(const ScriptValue& src, QVariantMap& dest) { dest.clear(); ScriptValueIteratorPointer iter = src.newIterator(); while (iter->hasNext()) { @@ -211,8 +110,7 @@ static bool VariantMapFromScriptValue(const ScriptValue& src, void* pDest) { return true; } -static ScriptValue VariantHashToScriptValue(ScriptEngine* engine, const void* pSrc) { - const QVariantHash& src = *reinterpret_cast(pSrc); +static ScriptValue VariantHashToScriptValue(ScriptEngine* engine, const QVariantHash& src) { ScriptValue dest = engine->newObject(); for (QVariantHash::const_iterator iter = src.cbegin(); iter != src.cend(); ++iter) { dest.setProperty(iter.key(), engine->newVariant(iter.value())); @@ -220,8 +118,7 @@ static ScriptValue VariantHashToScriptValue(ScriptEngine* engine, const void* pS return dest; } -static bool VariantHashFromScriptValue(const ScriptValue& src, void* pDest) { - QVariantHash& dest = *reinterpret_cast(pDest); +static bool VariantHashFromScriptValue(const ScriptValue& src, QVariantHash& dest) { dest.clear(); ScriptValueIteratorPointer iter = src.newIterator(); while (iter->hasNext()) { @@ -231,19 +128,16 @@ static bool VariantHashFromScriptValue(const ScriptValue& src, void* pDest) { return true; } -static ScriptValue JsonValueToScriptValue(ScriptEngine* engine, const void* pSrc) { - const QJsonValue& src = *reinterpret_cast(pSrc); +static ScriptValue JsonValueToScriptValue(ScriptEngine* engine, const QJsonValue& src) { return engine->newVariant(src.toVariant()); } -static bool JsonValueFromScriptValue(const ScriptValue& src, void* pDest) { - QJsonValue& dest = *reinterpret_cast(pDest); +static bool JsonValueFromScriptValue(const ScriptValue& src, QJsonValue& dest) { dest = QJsonValue::fromVariant(src.toVariant()); return true; } -static ScriptValue JsonObjectToScriptValue(ScriptEngine* engine, const void* pSrc) { - const QJsonObject& src = *reinterpret_cast(pSrc); +static ScriptValue JsonObjectToScriptValue(ScriptEngine* engine, const QJsonObject& src) { QVariantMap map = src.toVariantMap(); ScriptValue dest = engine->newObject(); for (QVariantMap::const_iterator iter = map.cbegin(); iter != map.cend(); ++iter) { @@ -252,8 +146,7 @@ static ScriptValue JsonObjectToScriptValue(ScriptEngine* engine, const void* pSr return dest; } -static bool JsonObjectFromScriptValue(const ScriptValue& src, void* pDest) { - QJsonObject& dest = *reinterpret_cast(pDest); +static bool JsonObjectFromScriptValue(const ScriptValue& src, QJsonObject& dest) { QVariantMap map; ScriptValueIteratorPointer iter = src.newIterator(); while (iter->hasNext()) { @@ -264,8 +157,7 @@ static bool JsonObjectFromScriptValue(const ScriptValue& src, void* pDest) { return true; } -static ScriptValue JsonArrayToScriptValue(ScriptEngine* engine, const void* pSrc) { - const QJsonArray& src = *reinterpret_cast(pSrc); +static ScriptValue JsonArrayToScriptValue(ScriptEngine* engine, const QJsonArray& src) { QVariantList list = src.toVariantList(); int len = list.length(); ScriptValue dest = engine->newArray(len); @@ -275,9 +167,8 @@ static ScriptValue JsonArrayToScriptValue(ScriptEngine* engine, const void* pSrc return dest; } -static bool JsonArrayFromScriptValue(const ScriptValue& src, void* pDest) { +static bool JsonArrayFromScriptValue(const ScriptValue& src, QJsonArray& dest) { if(!src.isArray()) return false; - QJsonArray& dest = *reinterpret_cast(pDest); QVariantList list; int len = src.property("length").toInteger(); for (int idx = 0; idx < len; ++idx) { @@ -292,63 +183,33 @@ static bool JsonArrayFromScriptValue(const ScriptValue& src, void* pDest) { void ScriptEngineQtScript::registerSystemTypes() { qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue); - QMutexLocker guard(&_customTypeProtect); - - { - CustomMarshal& customType = _customTypes.insert(QMetaType::QStringList, CustomMarshal()).value(); - customType.demarshalFunc = StringListFromScriptValue; - customType.marshalFunc = StringListToScriptValue; - } - { - CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantList, CustomMarshal()).value(); - customType.demarshalFunc = VariantListFromScriptValue; - customType.marshalFunc = VariantListToScriptValue; - } - { - CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantMap, CustomMarshal()).value(); - customType.demarshalFunc = VariantMapFromScriptValue; - customType.marshalFunc = VariantMapToScriptValue; - } - { - CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantHash, CustomMarshal()).value(); - customType.demarshalFunc = VariantHashFromScriptValue; - customType.marshalFunc = VariantHashToScriptValue; - } - { - CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonValue, CustomMarshal()).value(); - customType.demarshalFunc = JsonValueFromScriptValue; - customType.marshalFunc = JsonValueToScriptValue; - } - { - CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonObject, CustomMarshal()).value(); - customType.demarshalFunc = JsonObjectFromScriptValue; - customType.marshalFunc = JsonObjectToScriptValue; - } - { - CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonArray, CustomMarshal()).value(); - customType.demarshalFunc = JsonArrayFromScriptValue; - customType.marshalFunc = JsonArrayToScriptValue; - } + scriptRegisterMetaType(this, StringListToScriptValue, StringListFromScriptValue); + scriptRegisterMetaType(this, VariantListToScriptValue, VariantListFromScriptValue); + scriptRegisterMetaType(this, VariantMapToScriptValue, VariantMapFromScriptValue); + scriptRegisterMetaType(this, VariantHashToScriptValue, VariantHashFromScriptValue); + scriptRegisterMetaType(this, JsonValueToScriptValue, JsonValueFromScriptValue); + scriptRegisterMetaType(this, JsonObjectToScriptValue, JsonObjectFromScriptValue); + scriptRegisterMetaType(this, JsonArrayToScriptValue, JsonArrayFromScriptValue); } -bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& dest, int destType) { +bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& dest, int destTypeId) { // if we're not particularly interested in a specific type, try to detect if we're dealing with a registered type - if (destType == QMetaType::UnknownType) { + if (destTypeId == QMetaType::UnknownType) { QObject* obj = ScriptObjectQtProxy::unwrap(val); if (obj) { for (const QMetaObject* metaObject = obj->metaObject(); metaObject; metaObject = metaObject->superClass()) { QByteArray typeName = QByteArray(metaObject->className()) + "*"; int typeId = QMetaType::type(typeName.constData()); if (typeId != QMetaType::UnknownType) { - destType = typeId; + destTypeId = typeId; break; } } } } - if (destType == qMetaTypeId()) { + if (destTypeId == qMetaTypeId()) { dest = QVariant::fromValue(ScriptValue(new ScriptValueQtWrapper(this, val))); return true; } @@ -357,20 +218,19 @@ bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& ScriptEngine::DemarshalFunction demarshalFunc = nullptr; { QMutexLocker guard(&_customTypeProtect); - CustomMarshalMap::const_iterator lookup = _customTypes.find(destType); + CustomMarshalMap::const_iterator lookup = _customTypes.find(destTypeId); if (lookup != _customTypes.cend()) { demarshalFunc = lookup.value().demarshalFunc; } } if (demarshalFunc) { - void* destStorage = QMetaType::create(destType); + dest = QVariant(destTypeId, static_cast(NULL)); ScriptValue wrappedVal(new ScriptValueQtWrapper(this, val)); - bool success = demarshalFunc(wrappedVal, destStorage); - dest = success ? QVariant(destType, destStorage) : QVariant(); - QMetaType::destroy(destType, destStorage); + bool success = demarshalFunc(wrappedVal, const_cast(dest.constData())); + if(!success) dest = QVariant(); return success; } else { - switch (destType) { + switch (destTypeId) { case QMetaType::UnknownType: if (val.isUndefined()) { dest = QVariant(); @@ -443,8 +303,19 @@ bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& break; default: // check to see if this is a pointer to a QObject-derived object - if (QMetaType::typeFlags(destType) & QMetaType::PointerToQObject) { - dest = QVariant::fromValue(ScriptObjectQtProxy::unwrap(val)); + if (QMetaType::typeFlags(destTypeId) & (QMetaType::PointerToQObject | QMetaType::TrackingPointerToQObject)) { + /* Do we really want to permit regular passing of nullptr to native functions? + if (!val.isValid() || val.isUndefined() || val.isNull()) { + dest = QVariant::fromValue(nullptr); + break; + }*/ + QObject* obj = ScriptObjectQtProxy::unwrap(val); + if (!obj) return false; + const QMetaObject* destMeta = QMetaType::metaObjectForType(destTypeId); + Q_ASSERT(destMeta); + obj = destMeta->cast(obj); + if (!obj) return false; + dest = QVariant::fromValue(obj); break; } // check to see if we have a registered prototype @@ -461,7 +332,40 @@ bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& } } - return destType == QMetaType::UnknownType || dest.userType() == destType || dest.convert(destType); + return destTypeId == QMetaType::UnknownType || dest.userType() == destTypeId || dest.convert(destTypeId); +} + +QString ScriptEngineQtScript::valueType(const QScriptValue& val) { + if (val.isUndefined()) { + return "undefined"; + } + if (val.isNull()) { + return "null"; + } + if (val.isBool()) { + return "boolean"; + } + if (val.isString()) { + return "string"; + } + if (val.isNumber()) { + return "number"; + } + { + QObject* obj = ScriptObjectQtProxy::unwrap(val); + if (obj) { + QString objectName = obj->objectName(); + if (!objectName.isEmpty()) return objectName; + return obj->metaObject()->className(); + } + } + { + QVariant var = ScriptVariantQtProxy::unwrap(val); + if (var.isValid()) { + return var.typeName(); + } + } + return val.toVariant().typeName(); } QScriptValue ScriptEngineQtScript::castVariantToValue(const QVariant& val) { @@ -513,16 +417,21 @@ QScriptValue ScriptEngineQtScript::castVariantToValue(const QVariant& val) { return QScriptValue(this, val.toString()); case QMetaType::QVariant: return castVariantToValue(val.value()); - case QMetaType::QObjectStar: - return ScriptObjectQtProxy::newQObject(this, val.value(), ScriptEngine::QtOwnership); + case QMetaType::QObjectStar: { + QObject* obj = val.value(); + if (obj == nullptr) return QScriptValue(this, QScriptValue::NullValue); + return ScriptObjectQtProxy::newQObject(this, obj); + } case QMetaType::QDateTime: return static_cast(this)->newDate(val.value()); case QMetaType::QDate: return static_cast(this)->newDate(val.value().startOfDay()); default: // check to see if this is a pointer to a QObject-derived object - if (QMetaType::typeFlags(valTypeId) & QMetaType::PointerToQObject) { - return ScriptObjectQtProxy::newQObject(this, val.value(), ScriptEngine::QtOwnership); + if (QMetaType::typeFlags(valTypeId) & (QMetaType::PointerToQObject | QMetaType::TrackingPointerToQObject)) { + QObject* obj = val.value(); + if (obj == nullptr) return QScriptValue(this, QScriptValue::NullValue); + return ScriptObjectQtProxy::newQObject(this, obj); } // have we set a prototype'd variant? { diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp index f981534b07c..17b93e77d99 100644 --- a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp @@ -53,6 +53,18 @@ class ScriptPropertyContextQtWrapper final : public ScriptContext { QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObject* object, ScriptEngine::ValueOwnership ownership, const ScriptEngine::QObjectWrapOptions& options) { + QScriptEngine* qengine = static_cast(engine); + + // do we already have a valid wrapper for this QObject? + { + QMutexLocker guard(&engine->_qobjectWrapperMapProtect); + ScriptEngineQtScript::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object); + if (lookup != engine->_qobjectWrapperMap.end()) { + QSharedPointer proxy = lookup.value().lock(); + if (proxy) return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; + } + } + bool ownsObject; switch (ownership) { case ScriptEngine::QtOwnership: @@ -65,8 +77,33 @@ QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObje ownsObject = !object->parent(); break; } - QScriptEngine* qengine = static_cast(engine); + + // create the wrapper auto proxy = QSharedPointer::create(engine, object, ownsObject, options); + + { + QMutexLocker guard(&engine->_qobjectWrapperMapProtect); + + // check again to see if someone else created the wrapper while we were busy + ScriptEngineQtScript::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object); + if (lookup != engine->_qobjectWrapperMap.end()) { + QSharedPointer proxy = lookup.value().lock(); + if (proxy) return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; + } + + // register the wrapper with the engine and make sure it cleans itself up + engine->_qobjectWrapperMap.insert(object, proxy); + QPointer enginePtr = engine; + object->connect(object, &QObject::destroyed, engine, [enginePtr, object]() { + if (!enginePtr) return; + QMutexLocker guard(&enginePtr->_qobjectWrapperMapProtect); + ScriptEngineQtScript::ObjectWrapperMap::iterator lookup = enginePtr->_qobjectWrapperMap.find(object); + if (lookup != enginePtr->_qobjectWrapperMap.end()) { + enginePtr->_qobjectWrapperMap.erase(lookup); + } + }); + } + return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); } @@ -96,7 +133,6 @@ void ScriptObjectQtProxy::investigate() { if (!qobject) return; const QMetaObject* metaObject = qobject->metaObject(); - _name = QString::fromLatin1(metaObject->className()); // discover properties int startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassProperties ? metaObject->propertyOffset() : 0; @@ -185,6 +221,15 @@ void ScriptObjectQtProxy::investigate() { } } +QString ScriptObjectQtProxy::name() const { + Q_ASSERT(_object); + if (!_object) return ""; + return _object ? _object->objectName() : ""; + QString objectName = _object->objectName(); + if (!objectName.isEmpty()) return objectName; + return _object->metaObject()->className(); +} + QScriptClass::QueryFlags ScriptObjectQtProxy::queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) { // check for properties for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) { @@ -268,7 +313,7 @@ QScriptValue ScriptObjectQtProxy::property(const QScriptValue& object, const QSc MethodDefMap::const_iterator lookup = _methods.find(methodId); if (lookup == _methods.cend()) return QScriptValue(); return static_cast(_engine)->newObject( - new ScriptMethodQtProxy(_engine, qobject, object, name, lookup.value().methods)); + new ScriptMethodQtProxy(_engine, qobject, object, lookup.value().methods)); } case SIGNAL_TYPE: { int signalId = id & ~TYPE_MASK; @@ -278,7 +323,7 @@ QScriptValue ScriptObjectQtProxy::property(const QScriptValue& object, const QSc InstanceMap::const_iterator instLookup = _signalInstances.find(signalId); if (instLookup == _signalInstances.cend() || instLookup.value().isNull()) { instLookup = _signalInstances.insert(signalId, - new ScriptSignalQtProxy(_engine, qobject, object, name, defLookup.value().signal)); + new ScriptSignalQtProxy(_engine, qobject, object, defLookup.value().signal)); Q_ASSERT(instLookup != _signalInstances.cend()); } ScriptSignalQtProxy* proxy = instLookup.value(); @@ -315,10 +360,11 @@ void ScriptObjectQtProxy::setProperty(QScriptValue& object, const QScriptString& ScriptContextGuard guard(&ourContext); int propTypeId = prop.userType(); + Q_ASSERT(propTypeId != QMetaType::UnknownType); QVariant varValue; if(!_engine->castValueToVariant(value, varValue, propTypeId)) { QByteArray propTypeName = QMetaType(propTypeId).name(); - QByteArray valTypeName = value.toVariant().typeName(); + QByteArray valTypeName = _engine->valueType(value).toLatin1(); QScriptContext* currentContext = static_cast(_engine)->currentContext(); currentContext->throwError(QScriptContext::TypeError, QString("Cannot convert %1 to %2").arg(valTypeName, propTypeName)); return; @@ -352,6 +398,18 @@ QVariant ScriptVariantQtProxy::unwrap(const QScriptValue& val) { return proxy ? proxy->toQtValue() : QVariant(); } +QString ScriptMethodQtProxy::fullName() const { + Q_ASSERT(_object); + if (!_object) return ""; + Q_ASSERT(!_metas.isEmpty()); + const QMetaMethod& firstMethod = _metas.front(); + QString objectName = _object->objectName(); + if (!objectName.isEmpty()) { + return QString("%1.%2").arg(objectName, firstMethod.name()); + } + return QString("%1::%2").arg(_object->metaObject()->className(), firstMethod.name()); +} + bool ScriptMethodQtProxy::supportsExtension(Extension extension) const { switch (extension) { case Callable: @@ -377,6 +435,9 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg const int scriptValueTypeId = qMetaTypeId(); + int parameterConversionFailureId = 0; + int parameterConversionFailureCount = 0; + for (auto iter = _metas.cbegin(); iter != _metas.end(); ++iter) { const QMetaMethod& meta = *iter; int methodNumArgs = meta.parameterCount(); @@ -387,10 +448,10 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg QList qScriptArgList; QList qVarArgList; QGenericArgument qGenArgs[10]; - int arg; - bool conversionFailed = false; - for (arg = 0; arg < numArgs && !conversionFailed; ++arg) { + int conversionFailures = 0; + for (int arg = 0; arg < numArgs; ++arg) { int methodArgTypeId = meta.parameterType(arg); + Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); QScriptValue argVal = context->argument(arg); if (methodArgTypeId == scriptValueTypeId) { qScriptArgList.append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal))); @@ -401,24 +462,23 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg } else { QVariant varArgVal; if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) { - conversionFailed = true; - break; - /*QByteArray methodTypeName = QMetaType(methodArgTypeId).name(); - QByteArray argTypeName = argVal.toVariant().typeName(); - context->throwError(QScriptContext::TypeError, - QString("Cannot convert %1 to %2").arg(argTypeName, methodTypeName)); - return QVariant();*/ + conversionFailures++; + } else { + qVarArgList.append(varArgVal); + const QVariant& converted = qVarArgList.back(); + + // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant + // A const_cast is needed because calling data() would detach the QVariant. + qGenArgs[arg] = + QGenericArgument(QMetaType::typeName(converted.userType()), const_cast(converted.constData())); } - qVarArgList.append(varArgVal); - const QVariant& converted = qVarArgList.back(); - - // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant - // A const_cast is needed because calling data() would detach the QVariant. - qGenArgs[arg] = - QGenericArgument(QMetaType::typeName(converted.userType()), const_cast(converted.constData())); } } - if (conversionFailed) { + if (conversionFailures) { + if (conversionFailures < parameterConversionFailureCount || !parameterConversionFailureCount) { + parameterConversionFailureCount = conversionFailures; + parameterConversionFailureId = meta.methodIndex(); + } continue; } @@ -426,11 +486,18 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg ScriptContextGuard guard(&ourContext); int returnTypeId = meta.returnType(); - if (returnTypeId == QMetaType::Void) { + + // The Qt MOC engine will automatically call qRegisterMetaType on invokable parameters and properties, but there's + // nothing in there for return values so these need to be explicitly runtime-registered! + Q_ASSERT(returnTypeId != QMetaType::UnknownType); + if (returnTypeId == QMetaType::UnknownType) { + context->throwError(QString("Cannot call native function %1, its return value has not been registered with Qt").arg(fullName())); + return QVariant(); + } else if (returnTypeId == QMetaType::Void) { bool success = meta.invoke(qobject, Qt::DirectConnection, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); if (!success) { - context->throwError("Native call failed"); + context->throwError(QString("Unexpected: Native call of %1 failed").arg(fullName())); } return QVariant(); } else if (returnTypeId == scriptValueTypeId) { @@ -439,7 +506,7 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); if (!success) { - context->throwError("Native call failed"); + context->throwError(QString("Unexpected: Native call of %1 failed").arg(fullName())); return QVariant(); } QScriptValue qResult = ScriptValueQtWrapper::fullUnwrap(_engine, result); @@ -454,15 +521,53 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); if (!success) { - context->throwError("Native call failed"); + context->throwError(QString("Unexpected: Native call of %1 failed").arg(fullName())); return QVariant(); } QScriptValue qResult = _engine->castVariantToValue(qRetVal); return QVariant::fromValue(qResult); } } - context->throwError("Native call failed: could not locate an overload with the requested arguments"); + + // we failed to convert the call to C++, try to create a somewhat sane error message + if (parameterConversionFailureCount == 0) { + context->throwError(QString("Native call of %1 failed: unexpected parameter count").arg(fullName())); + return QVariant(); + } + + const QMetaMethod& meta = _object->metaObject()->method(parameterConversionFailureId); + int methodNumArgs = meta.parameterCount(); + Q_ASSERT(methodNumArgs == numArgs); + + for (int arg = 0; arg < numArgs; ++arg) { + int methodArgTypeId = meta.parameterType(arg); + Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); + QScriptValue argVal = context->argument(arg); + if (methodArgTypeId != scriptValueTypeId && methodArgTypeId != QMetaType::QVariant) { + QVariant varArgVal; + if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) { + QByteArray methodTypeName = QMetaType(methodArgTypeId).name(); + QByteArray argTypeName = _engine->valueType(argVal).toLatin1(); + context->throwError(QScriptContext::TypeError, QString("Native call of %1 failed: Cannot convert parameter %2 from %3 to %4") + .arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName)); + return QVariant(); + } + } + } + + Q_ASSERT(false); // really shouldn't have gotten here -- it didn't work before and it's working now? return QVariant(); + context->throwError(QString("Native call of %1 failed: could not locate an overload with the requested arguments").arg(fullName())); +} + +QString ScriptSignalQtProxy::fullName() const { + Q_ASSERT(_object); + if (!_object) return ""; + QString objectName = _object->objectName(); + if (!objectName.isEmpty()) { + return QString("%1.%2").arg(objectName, _meta.name()); + } + return QString("%1::%2").arg(_object->metaObject()->className(), _meta.name()); } // Adapted from https://doc.qt.io/archives/qq/qq16-dynamicqobject.html, for connecting to a signal without a compile-time definition for it @@ -476,6 +581,7 @@ int ScriptSignalQtProxy::qt_metacall(QMetaObject::Call call, int id, void** argu int numArgs = _meta.parameterCount(); for (int arg = 0; arg < numArgs; ++arg) { int methodArgTypeId = _meta.parameterType(arg); + Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); QVariant argValue(methodArgTypeId, arguments[arg+1]); args.append(_engine->castVariantToValue(argValue)); } diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h index efd9070bb36..a3844a8e532 100644 --- a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h @@ -73,7 +73,7 @@ class ScriptObjectQtProxy final : public QScriptClass { inline QObject* toQtValue() const { return _object; } public: // QScriptClass implementation - virtual QString name() const override { return _name; } + virtual QString name() const override; virtual QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override; virtual QScriptValue::PropertyFlags propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) override; @@ -92,7 +92,6 @@ class ScriptObjectQtProxy final : public QScriptClass { InstanceMap _signalInstances; const bool _ownsObject; QPointer _object; - QString _name; Q_DISABLE_COPY(ScriptObjectQtProxy) }; @@ -138,19 +137,21 @@ class ScriptVariantQtProxy final : public QScriptClass { class ScriptMethodQtProxy final : public QScriptClass { public: // construction - inline ScriptMethodQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, QString name, const QList& metas) : - QScriptClass(engine), _engine(engine), _object(object), _objectLifetime(lifetime), _name(name), _metas(metas) {} + inline ScriptMethodQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, const QList& metas) : + QScriptClass(engine), _engine(engine), _object(object), _objectLifetime(lifetime), _metas(metas) {} public: // QScriptClass implementation - virtual QString name() const override { return _name; } + virtual QString name() const override { return fullName(); } virtual bool supportsExtension(Extension extension) const override; virtual QVariant extension(Extension extension, const QVariant& argument = QVariant()) override; +private: + QString fullName() const; + private: // storage ScriptEngineQtScript* _engine; QPointer _object; QScriptValue _objectLifetime; - const QString _name; const QList _metas; Q_DISABLE_COPY(ScriptMethodQtProxy) @@ -175,13 +176,14 @@ class ScriptSignalQtProxy final : public ScriptSignalQtProxyBase { using ConnectionList = QList; public: // construction - inline ScriptSignalQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, QString name, const QMetaMethod& meta) : - _engine(engine), _object(object), _objectLifetime(lifetime), _name(name), _meta(meta), _metaCallId(discoverMetaCallIdx()) {} + inline ScriptSignalQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, const QMetaMethod& meta) : + _engine(engine), _object(object), _objectLifetime(lifetime), _meta(meta), _metaCallId(discoverMetaCallIdx()) {} private: // implementation virtual int qt_metacall(QMetaObject::Call call, int id, void** arguments); int discoverMetaCallIdx(); ConnectionList::iterator findConnection(QScriptValue thisObject, QScriptValue callback); + QString fullName() const; public: // API virtual void connect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) override; @@ -191,7 +193,6 @@ class ScriptSignalQtProxy final : public ScriptSignalQtProxyBase { ScriptEngineQtScript* _engine; QPointer _object; QScriptValue _objectLifetime; - QString _name; const QMetaMethod _meta; const int _metaCallId; ConnectionList _connections; From 7a4915514d4e07a5bdc8b92e2d707e2956d35961 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Wed, 19 Jan 2022 21:36:37 -0800 Subject: [PATCH 27/34] minor tweaks in response to code review (very belated) and reported issues - explicitly registering some enums with Qt at runtime (needed if they're function return values) - replaced references to engine() with local variables if they already existed --- interface/src/scripting/PerformanceScriptingInterface.cpp | 2 ++ interface/src/scripting/RenderScriptingInterface.cpp | 1 + libraries/script-engine/src/qtscript/ArrayBufferClass.cpp | 2 +- .../script-engine/src/qtscript/ScriptObjectQtProxy.cpp | 8 ++++---- libraries/ui/src/ui/TabletScriptingInterface.cpp | 2 ++ 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/interface/src/scripting/PerformanceScriptingInterface.cpp b/interface/src/scripting/PerformanceScriptingInterface.cpp index ec56e833238..fb4561aea8d 100644 --- a/interface/src/scripting/PerformanceScriptingInterface.cpp +++ b/interface/src/scripting/PerformanceScriptingInterface.cpp @@ -16,6 +16,8 @@ std::once_flag PerformanceScriptingInterface::registry_flag; PerformanceScriptingInterface::PerformanceScriptingInterface() { std::call_once(registry_flag, [] { qmlRegisterType("PerformanceEnums", 1, 0, "PerformanceEnums"); + qRegisterMetaType("PerformanceScriptingInterface::PerformancePreset"); + qRegisterMetaType("PerformanceScriptingInterface::RefreshRateProfile"); }); } diff --git a/interface/src/scripting/RenderScriptingInterface.cpp b/interface/src/scripting/RenderScriptingInterface.cpp index 5ecb1a6e43a..aec7ae3b4cd 100644 --- a/interface/src/scripting/RenderScriptingInterface.cpp +++ b/interface/src/scripting/RenderScriptingInterface.cpp @@ -20,6 +20,7 @@ std::once_flag RenderScriptingInterface::registry_flag; RenderScriptingInterface::RenderScriptingInterface() { std::call_once(registry_flag, [] { qmlRegisterType("RenderEnums", 1, 0, "RenderEnums"); + qRegisterMetaType("RenderScriptingInterface::RenderMethod"); }); } diff --git a/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp b/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp index e5ae13e7d41..ef4b3567440 100644 --- a/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp +++ b/libraries/script-engine/src/qtscript/ArrayBufferClass.cpp @@ -86,7 +86,7 @@ QScriptValue ArrayBufferClass::newInstance(qint32 size) { QScriptValue ArrayBufferClass::newInstance(const QByteArray& ba) { QScriptEngine* eng = engine(); QScriptValue data = eng->newVariant(QVariant::fromValue(ba)); - return engine()->newObject(this, data); + return eng->newObject(this, data); } QScriptValue ArrayBufferClass::construct(QScriptContext* context, QScriptEngine* engine) { diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp index 17b93e77d99..02dbd318507 100644 --- a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp @@ -61,7 +61,7 @@ QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObje ScriptEngineQtScript::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object); if (lookup != engine->_qobjectWrapperMap.end()) { QSharedPointer proxy = lookup.value().lock(); - if (proxy) return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; + if (proxy) return qengine->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; } } @@ -88,7 +88,7 @@ QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObje ScriptEngineQtScript::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object); if (lookup != engine->_qobjectWrapperMap.end()) { QSharedPointer proxy = lookup.value().lock(); - if (proxy) return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; + if (proxy) return qengine->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; } // register the wrapper with the engine and make sure it cleans itself up @@ -104,7 +104,7 @@ QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObje }); } - return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); + return qengine->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); } ScriptObjectQtProxy* ScriptObjectQtProxy::unwrapProxy(const QScriptValue& val) { @@ -385,7 +385,7 @@ QScriptValue ScriptVariantQtProxy::newVariant(ScriptEngineQtScript* engine, cons return qengine->newVariant(variant); } auto proxy = QSharedPointer::create(engine, variant, proto, protoProxy); - return static_cast(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); + return qengine->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); } ScriptVariantQtProxy* ScriptVariantQtProxy::unwrapProxy(const QScriptValue& val) { diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 68730e186fd..81a4e9c7185 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -159,6 +159,8 @@ bool TabletButtonsProxyModel::filterAcceptsRow(int sourceRow, TabletScriptingInterface::TabletScriptingInterface() { qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletEnums"); + qRegisterMetaType("TabletScriptingInterface::TabletAudioEvents"); + qRegisterMetaType("TabletScriptingInterface::TabletConstants"); qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletButtonsProxyModel"); } From 81989910972d7a1b5a733c78a79600961c4ca6b3 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 20 Mar 2022 22:08:25 -0700 Subject: [PATCH 28/34] force Qt registration of PerformanceManager::PerformancePreset, as it's used as a return datatype in a script-callable function (and doesn't get auto-registered) --- interface/src/PerformanceManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/PerformanceManager.cpp b/interface/src/PerformanceManager.cpp index 190071724a6..090c72d07e8 100644 --- a/interface/src/PerformanceManager.cpp +++ b/interface/src/PerformanceManager.cpp @@ -19,7 +19,11 @@ PerformanceManager::PerformanceManager() { - setPerformancePreset((PerformancePreset) _performancePresetSetting.get()); + static std::once_flag registry_flag; + std::call_once(registry_flag, [] { + qRegisterMetaType("PerformanceManager::PerformancePreset"); + }); + setPerformancePreset((PerformancePreset)_performancePresetSetting.get()); } void PerformanceManager::setupPerformancePresetSettings(bool evaluatePlatformTier) { From e30cf4193b16c61f658074c69401c94b52edc7ed Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 20 Mar 2022 22:12:34 -0700 Subject: [PATCH 29/34] identify the largest number of parameters any of our method overrides accept and discard script parameters beyond that count --- .../script-engine/src/qtscript/ScriptObjectQtProxy.cpp | 9 ++++++--- .../script-engine/src/qtscript/ScriptObjectQtProxy.h | 8 ++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp index 02dbd318507..96a867b7a2a 100644 --- a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp @@ -205,9 +205,11 @@ void ScriptObjectQtProxy::investigate() { } } } else { + int parameterCount = method.parameterCount(); if (nameLookup == methodNames.end()) { MethodDef& methodDef = _methods.insert(idx, MethodDef()).value(); methodDef.name = name; + methodDef.numMaxParms = parameterCount; methodDef.methods.append(method); methodNames.insert(name, idx); } else { @@ -215,6 +217,7 @@ void ScriptObjectQtProxy::investigate() { MethodDefMap::iterator methodLookup = _methods.find(originalMethodId); Q_ASSERT(methodLookup != _methods.end()); MethodDef& methodDef = methodLookup.value(); + if(methodDef.numMaxParms < parameterCount) methodDef.numMaxParms = parameterCount; methodDef.methods.append(method); } } @@ -312,8 +315,9 @@ QScriptValue ScriptObjectQtProxy::property(const QScriptValue& object, const QSc int methodId = id & ~TYPE_MASK; MethodDefMap::const_iterator lookup = _methods.find(methodId); if (lookup == _methods.cend()) return QScriptValue(); + const MethodDef& methodDef = lookup.value(); return static_cast(_engine)->newObject( - new ScriptMethodQtProxy(_engine, qobject, object, lookup.value().methods)); + new ScriptMethodQtProxy(_engine, qobject, object, methodDef.methods, methodDef.numMaxParms)); } case SIGNAL_TYPE: { int signalId = id & ~TYPE_MASK; @@ -430,8 +434,7 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg } int scriptNumArgs = context->argumentCount(); - Q_ASSERT(scriptNumArgs < 10); - int numArgs = std::min(scriptNumArgs, 10); + int numArgs = std::min(scriptNumArgs, _numMaxParms); const int scriptValueTypeId = qMetaTypeId(); diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h index a3844a8e532..34ee8526119 100644 --- a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h @@ -41,6 +41,7 @@ class ScriptObjectQtProxy final : public QScriptClass { }; struct MethodDef { QScriptString name; + int numMaxParms; QList methods; }; struct SignalDef { @@ -137,8 +138,10 @@ class ScriptVariantQtProxy final : public QScriptClass { class ScriptMethodQtProxy final : public QScriptClass { public: // construction - inline ScriptMethodQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, const QList& metas) : - QScriptClass(engine), _engine(engine), _object(object), _objectLifetime(lifetime), _metas(metas) {} + inline ScriptMethodQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, + const QList& metas, int numMaxParms) : + QScriptClass(engine), + _engine(engine), _object(object), _objectLifetime(lifetime), _metas(metas), _numMaxParms(numMaxParms) {} public: // QScriptClass implementation virtual QString name() const override { return fullName(); } @@ -149,6 +152,7 @@ class ScriptMethodQtProxy final : public QScriptClass { QString fullName() const; private: // storage + const int _numMaxParms; ScriptEngineQtScript* _engine; QPointer _object; QScriptValue _objectLifetime; From e9ed54322ec29c98698e2b290e447148f8097736 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Sun, 20 Mar 2022 22:15:32 -0700 Subject: [PATCH 30/34] fix typo preventing methods from being discovered on scriptable objects when we're ignoring superclasses --- libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp index 96a867b7a2a..7f09479ee49 100644 --- a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp @@ -158,7 +158,7 @@ void ScriptObjectQtProxy::investigate() { } // discover methods - startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassMethods ? metaObject->methodCount() : 0; + startIdx = (_wrapOptions & ScriptEngine::ExcludeSuperClassMethods) ? metaObject->methodOffset() : 0; num = metaObject->methodCount(); QHash methodNames; for (int idx = startIdx; idx < num; ++idx) { From 9029337d97d387aa2fe0ee6d991802a1ccc181ba Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Mon, 21 Mar 2022 00:24:27 -0700 Subject: [PATCH 31/34] remove requirement that ScriptManager::evaluate be meta-invokable --- interface/src/ui/JSConsole.cpp | 7 ++-- libraries/shared/src/shared/QtHelpers.cpp | 10 ++++++ libraries/shared/src/shared/QtHelpers.h | 44 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 89b20918d77..7d4fadab8e5 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -355,10 +355,9 @@ void JSConsole::executeCommand(const QString& command) { ScriptValue result; auto scriptManager = weakScriptManager.lock(); if (scriptManager) { - BLOCKING_INVOKE_METHOD(scriptManager.get(), "evaluate", - Q_RETURN_ARG(ScriptValue, result), - Q_ARG(const QString&, command), - Q_ARG(const QString&, consoleFileName)); + BLOCKING_INVOKE_METHOD(scriptManager.get(), [&scriptManager, &consoleFileName, &command, &result]() -> void { + result = scriptManager->evaluate(command, consoleFileName); + }); } return result; }); diff --git a/libraries/shared/src/shared/QtHelpers.cpp b/libraries/shared/src/shared/QtHelpers.cpp index ed387a97634..477176ecb9a 100644 --- a/libraries/shared/src/shared/QtHelpers.cpp +++ b/libraries/shared/src/shared/QtHelpers.cpp @@ -40,6 +40,16 @@ void addBlockingForbiddenThread(const QString& name, QThread* thread) { threadHash[thread] = name; } +QString isBlockingForbiddenThread(QThread* currentThread) { + QReadLocker locker(&threadHashLock); + for (const auto& thread : threadHash.keys()) { + if (currentThread == thread) { + return threadHash[thread]; + } + } + return QString(); +} + bool blockingInvokeMethod( const char* function, QObject *obj, const char *member, diff --git a/libraries/shared/src/shared/QtHelpers.h b/libraries/shared/src/shared/QtHelpers.h index 9a9d33a3ceb..b87caf01854 100644 --- a/libraries/shared/src/shared/QtHelpers.h +++ b/libraries/shared/src/shared/QtHelpers.h @@ -11,14 +11,21 @@ #define hifi_Shared_QtHelpers_h #include +#include + +#include "../Profile.h" #if defined(Q_OS_WIN) // Enable event queue debugging #define DEBUG_EVENT_QUEUE #endif +class QLoggingCategory; +const QLoggingCategory& thread_safety(); + namespace hifi { namespace qt { void addBlockingForbiddenThread(const QString& name, QThread* thread = nullptr); +QString isBlockingForbiddenThread(QThread* currentThread); bool blockingInvokeMethod( const char* function, @@ -49,6 +56,43 @@ bool blockingInvokeMethod( QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()); +// handling unregistered functions +template +typename std::enable_if::value, bool>::type +blockingInvokeMethod(const char* callingFunction, QObject* context, Func function, ReturnType* retVal) { + auto currentThread = QThread::currentThread(); + if (currentThread == qApp->thread()) { + qCWarning(thread_safety) << "BlockingQueuedConnection invoked on main thread from " << callingFunction; + return QMetaObject::invokeMethod(context, function, Qt::BlockingQueuedConnection, retVal); + } + + QString forbiddenThread = isBlockingForbiddenThread(currentThread); + if (!forbiddenThread.isEmpty()) { + qCWarning(thread_safety) << "BlockingQueuedConnection invoked on forbidden thread " << forbiddenThread; + } + + PROFILE_RANGE(app, callingFunction); + return QMetaObject::invokeMethod(context, function, Qt::BlockingQueuedConnection, retVal); +} + +template +typename std::enable_if::value, bool>::type +blockingInvokeMethod(const char* callingFunction, QObject* context, Func function) { + auto currentThread = QThread::currentThread(); + if (currentThread == qApp->thread()) { + qCWarning(thread_safety) << "BlockingQueuedConnection invoked on main thread from " << callingFunction; + return QMetaObject::invokeMethod(context, function, Qt::BlockingQueuedConnection); + } + + QString forbiddenThread = isBlockingForbiddenThread(currentThread); + if (!forbiddenThread.isEmpty()) { + qCWarning(thread_safety) << "BlockingQueuedConnection invoked on forbidden thread " << forbiddenThread; + } + + PROFILE_RANGE(app, callingFunction); + return QMetaObject::invokeMethod(context, function, Qt::BlockingQueuedConnection); +} + // Inspecting of the qt event queue // requres access to private Qt datastructures // Querying the event queue should be done with From 6f9e77ea5c44a9a53ee977da4cfa58c1f29af988 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Mon, 21 Mar 2022 00:45:59 -0700 Subject: [PATCH 32/34] dropped unused meta declaration --- libraries/controllers/src/controllers/ScriptingInterface.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index 6f84255b4ba..2187f4bc996 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -30,8 +30,6 @@ #include #include -Q_DECLARE_METATYPE(controller::InputController*) -//static int inputControllerPointerId = qRegisterMetaType(); ScriptValue inputControllerToScriptValue(ScriptEngine* engine, controller::InputController* const& in) { return engine->newQObject(in, ScriptEngine::QtOwnership); From 32584b7d81815d4082d5addb3fc68f9b24b53691 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Mon, 21 Mar 2022 00:47:10 -0700 Subject: [PATCH 33/34] dropped KALILA global script attributes --- libraries/script-engine/src/ScriptManager.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 81d99521415..7addbe080a3 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -715,10 +715,6 @@ void ScriptManager::init() { scriptEngine->registerGlobalObject("StackTest", new StackTestScriptingInterface(this)); #endif - scriptEngine->globalObject().setProperty("KALILA", "isWaifu"); - scriptEngine->globalObject().setProperty("Kute", scriptEngine->newFunction([](ScriptContext* context, ScriptEngine* engine) -> ScriptValue { - return context->engine()->newValue(context->argument(0).toString().toLower() == "kalila" ? true : false); - })); } // registers a global object by name From 52c834482cb048cd8fa7daf1dbd6d826ac15cd78 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Mon, 21 Mar 2022 22:53:44 -0700 Subject: [PATCH 34/34] fixed missing #include required by new template blockingInvokeMethod functions --- libraries/shared/src/shared/QtHelpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/shared/QtHelpers.h b/libraries/shared/src/shared/QtHelpers.h index b87caf01854..5e317727fd1 100644 --- a/libraries/shared/src/shared/QtHelpers.h +++ b/libraries/shared/src/shared/QtHelpers.h @@ -12,6 +12,7 @@ #include #include +#include #include "../Profile.h"