From 277f5ef3a4527efd9a6c0d1f96a8ada6ee455dda Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Sat, 23 May 2015 13:35:35 -0700 Subject: [PATCH] Working experimental first version. --- .../src/EntityTreeRenderer.cpp | 19 +++++++++++++++ .../src/EntityTreeRenderer.h | 4 ++++ .../entities/src/EntityScriptingInterface.cpp | 7 ++++++ .../entities/src/EntityScriptingInterface.h | 8 +++++++ libraries/script-engine/src/ScriptEngine.cpp | 24 +++++++++++++++++++ libraries/script-engine/src/ScriptEngine.h | 8 +++++++ 6 files changed, 70 insertions(+) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c47c24f20a..a41f23a7cc 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -873,6 +873,23 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity); connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity); + connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity); + + connect(entityScriptingInterface, &EntityScriptingInterface::addEntityEventHandler, this, &EntityTreeRenderer::addEntityEventHandler); + connect(entityScriptingInterface, &EntityScriptingInterface::removeEntityEventHandler, this, &EntityTreeRenderer::addEntityEventHandler); +} + +void EntityTreeRenderer::addEntityEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler) { + ScriptEngine* engine = static_cast(handler.engine()); + if (engine) { // In case it's gone by the time we get the signal + engine->addEntityEventHandler(entityID, entityEventName, handler); + } +} +void EntityTreeRenderer::removeEntityEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler) { + ScriptEngine* engine = static_cast(handler.engine()); + if (engine) { + engine->removeEntityEventHandler(entityID, entityEventName, handler); + } } QScriptValueList EntityTreeRenderer::createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID) { @@ -1187,6 +1204,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons playEntityCollisionSound(myNodeID, entityTree, idB, collision); // And now the entity scripts + emit collisionWithEntity(idA, idB, collision); QScriptValue entityScriptA = loadEntityScript(idA); if (entityScriptA.property("collisionWithEntity").isValid()) { QScriptValueList args; @@ -1196,6 +1214,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons entityScriptA.property("collisionWithEntity").call(entityScriptA, args); } + emit collisionWithEntity(idB, idB, collision); QScriptValue entityScriptB = loadEntityScript(idB); if (entityScriptB.property("collisionWithEntity").isValid()) { QScriptValueList args; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 9768d4a20a..2c841e6f06 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -107,6 +107,7 @@ signals: void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); + void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); public slots: void addingEntity(const EntityItemID& entityID); @@ -121,6 +122,9 @@ public slots: void setDisplayModelElementProxy(bool value) { _displayModelElementProxy = value; } void setDontDoPrecisionPicking(bool value) { _dontDoPrecisionPicking = value; } + void addEntityEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler); + void removeEntityEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler); + protected: virtual Octree* createTree() { return new EntityTree(true); } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 351bbc3643..a23bb386ff 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -201,6 +201,13 @@ void EntityScriptingInterface::dumpTree() const { } } +void EntityScriptingInterface::addEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler) { + emit addEntityEventHandler(entityID, entityEventName, handler); +} +void EntityScriptingInterface::removeEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler) { + emit removeEntityEventHandler(entityID, entityEventName, handler); +} + QVector EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const { QVector result; if (_entityTree) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index f1876a836b..c04e55a8a0 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -119,8 +119,16 @@ public slots: Q_INVOKABLE void dumpTree() const; + // Register a function that will handle the given entityEventName on entityID + Q_INVOKABLE void addEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler); + Q_INVOKABLE void removeEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler); + signals: + void addEntityEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler); + void removeEntityEventHandler(EntityItemID entityID, QString entityEventName, QScriptValue handler); + void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); + void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); void canAdjustLocksChanged(bool canAdjustLocks); void canRezChanged(bool canRez); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 427944e254..81e30d0265 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -389,6 +389,30 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func } } +void ScriptEngine::addEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { + auto entities = DependencyManager::get(); + if (!_registeredHandlers.contains(entityID)) { + _registeredHandlers[entityID] = RegisteredEventHandlers(); + } + _registeredHandlers[entityID][eventName] = handler; + if (eventName == "collisionWithEntity") { + connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, &ScriptEngine::collisionWithEntity); + } + // FIXME: deletingEntity, changingEntityID +} +void ScriptEngine::removeEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { + // FIXME +} +void ScriptEngine::collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { + if (!_registeredHandlers.contains(idA)) return; + const RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[idA]; + if (!handlersOnEntity.contains("collisionWithEntity")) return; + // FIXME: Need one more level of indirection. We need to allow multiple handlers per event, registered by different scripts. + QScriptValue handlerForEvent = handlersOnEntity["collisionWithEntity"]; + QScriptValueList args = QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); + handlerForEvent.call(QScriptValue(), args); +} + void ScriptEngine::evaluate() { if (_stoppingAllScripts) { return; // bail early diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 45e56850a7..5aab43dff0 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -31,11 +31,14 @@ #include "ScriptCache.h" #include "ScriptUUID.h" #include "Vec3.h" +#include "EntityItemID.h" const QString NO_SCRIPT(""); const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5); +typedef QHash RegisteredEventHandlers; + class ScriptEngine : public QScriptEngine, public ScriptUser { Q_OBJECT public: @@ -98,6 +101,9 @@ public: virtual void scriptContentsAvailable(const QUrl& url, const QString& scriptContents); virtual void errorInLoadingScript(const QUrl& url); + void addEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler); + void removeEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler); + public slots: void loadURL(const QUrl& scriptURL); void stop(); @@ -114,6 +120,7 @@ public slots: QUrl resolvePath(const QString& path) const; void nodeKilled(SharedNodePointer node); + void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); signals: void scriptLoaded(const QString& scriptFilename); @@ -164,6 +171,7 @@ private: ArrayBufferClass* _arrayBufferClass; QHash _outgoingScriptAudioSequenceNumbers; + QHash _registeredHandlers; private: static QSet _allKnownScriptEngines;