Working experimental first version.

This commit is contained in:
Howard Stearns 2015-05-23 13:35:35 -07:00
parent 8c0bf19536
commit 277f5ef3a4
6 changed files with 70 additions and 0 deletions

View file

@ -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<ScriptEngine*>(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<ScriptEngine*>(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;

View file

@ -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); }

View file

@ -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<QUuid> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const {
QVector<QUuid> result;
if (_entityTree) {

View file

@ -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);

View file

@ -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<EntityScriptingInterface>();
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

View file

@ -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<QString, QScriptValue> 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<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
QHash<EntityItemID, RegisteredEventHandlers> _registeredHandlers;
private:
static QSet<ScriptEngine*> _allKnownScriptEngines;