diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 2bfcdcdf8c..2e74e889a6 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -85,6 +85,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket"); packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket"); packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); + packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket"); static const int LOG_INTERVAL = MSECS_PER_SECOND / 10; auto timer = new QTimer(this); @@ -231,6 +232,33 @@ void EntityScriptServer::pushLogs() { } } +void EntityScriptServer::handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode) { + + if (_entitiesScriptEngine && _entityViewer.getTree() && !_shuttingDown) { + auto entityID = QUuid::fromRfc4122(receivedMessage->read(NUM_BYTES_RFC4122_UUID)); + + quint16 methodLength; + receivedMessage->readPrimitive(&methodLength); + auto methodData = receivedMessage->read(methodLength); + auto method = QString::fromUtf8(methodData); + + quint16 paramCount; + receivedMessage->readPrimitive(¶mCount); + + QStringList params; + for (int param = 0; param < paramCount; param++) { + quint16 paramLength; + receivedMessage->readPrimitive(¶mLength); + auto paramData = receivedMessage->read(paramLength); + auto paramString = QString::fromUtf8(paramData); + params << paramString; + } + + _entitiesScriptEngine->callEntityScriptMethod(entityID, method, params); + } +} + + void EntityScriptServer::run() { // make sure we request our script once the agent connects to the domain auto nodeList = DependencyManager::get(); diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index e6bd12460b..f9c5e921f0 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -54,6 +54,9 @@ private slots: void pushLogs(); + void handleEntityScriptCallMethodPacket(QSharedPointer message, SharedNodePointer senderNode); + + private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f5117dddc0..39f19323e3 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -566,6 +566,11 @@ void EntityScriptingInterface::callEntityMethod(QUuid id, const QString& method, } } +void EntityScriptingInterface::callEntityServerMethod(QUuid id, const QString& method, const QStringList& params) { + PROFILE_RANGE(script_entities, __FUNCTION__); + DependencyManager::get()->callEntityServerMethod(id, method, params); +} + QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { PROFILE_RANGE(script_entities, __FUNCTION__); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 989d3dd89d..ee5011e99d 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -188,11 +188,11 @@ public slots: */ Q_INVOKABLE void deleteEntity(QUuid entityID); - /// Allows a script to call a method on an entity's script. The method will execute in the entity script - /// engine. If the entity does not have an entity script or the method does not exist, this call will have - /// no effect. /**jsdoc - * Call a method on an entity. If it is running an entity script (specified by the `script` property) + * Call a method on an entity. Allows a script to call a method on an entity's script. + * The method will execute in the entity script engine. If the entity does not have an + * entity script or the method does not exist, this call will have no effect. + * If it is running an entity script (specified by the `script` property) * and it exposes a property with the specified name `method`, it will be called * using `params` as the list of arguments. * @@ -203,10 +203,29 @@ public slots: */ Q_INVOKABLE void callEntityMethod(QUuid entityID, const QString& method, const QStringList& params = QStringList()); - /// finds the closest model to the center point, within the radius - /// will return a EntityItemID.isKnownID = false if no models are in the radius - /// this function will not find any models in script engine contexts which don't have access to models /**jsdoc + * Call a server method on an entity. Allows a client entity script to call a method on an + * entity's server script. The method will execute in the entity server script engine. If + * the entity does not have an entity server script or the method does not exist, this call will + * have no effect. If the entity is running an entity script (specified by the `serverScripts` property) + * and it exposes a property with the specified name `method`, it will be called using `params` as + * the list of arguments. + * + * @function Entities.callEntityServerMethod + * @param {EntityID} entityID The ID of the entity to call the method on. + * @param {string} method The name of the method to call. + * @param {string[]} params The list of parameters to call the specified method with. + */ + Q_INVOKABLE void callEntityServerMethod(QUuid entityID, const QString& method, const QStringList& params = QStringList()); + + /**jsdoc + * finds the closest model to the center point, within the radius + * will return a EntityItemID.isKnownID = false if no models are in the radius + * this function will not find any models in script engine contexts which don't have access to models + * @function Entities.findClosestEntity + * @param {vec3} center point + * @param {float} radius to search + * @return {EntityID} The EntityID of the entity that is closest and in the radius. */ Q_INVOKABLE QUuid findClosestEntity(const glm::vec3& center, float radius) const; diff --git a/libraries/networking/src/EntityScriptClient.cpp b/libraries/networking/src/EntityScriptClient.cpp index ef59ec99b8..2d47b8d8a3 100644 --- a/libraries/networking/src/EntityScriptClient.cpp +++ b/libraries/networking/src/EntityScriptClient.cpp @@ -69,6 +69,36 @@ bool EntityScriptClient::reloadServerScript(QUuid entityID) { return false; } +void EntityScriptClient::callEntityServerMethod(QUuid entityID, const QString& method, const QStringList& params) { + // Send packet to entity script server + auto nodeList = DependencyManager::get(); + SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer); + + if (entityScriptServer) { + auto packetList = NLPacketList::create(PacketType::EntityScriptCallMethod, QByteArray(), true, true); + + packetList->write(entityID.toRfc4122()); + + auto methodUtf8 = method.toUtf8(); + quint16 methodLength = methodUtf8.length(); + packetList->writePrimitive(methodLength); + packetList->write(methodUtf8); + + quint16 paramCount = params.length(); + packetList->writePrimitive(paramCount); + + foreach(const QString& param, params) { + auto paramUtf8 = param.toUtf8(); + quint16 paramLength = paramUtf8.length(); + packetList->writePrimitive(paramLength); + packetList->write(paramUtf8); + } + + nodeList->sendPacketList(std::move(packetList), *entityScriptServer); + } +} + + MessageID EntityScriptClient::getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer); diff --git a/libraries/networking/src/EntityScriptClient.h b/libraries/networking/src/EntityScriptClient.h index 926521d9b8..6f1a0376ea 100644 --- a/libraries/networking/src/EntityScriptClient.h +++ b/libraries/networking/src/EntityScriptClient.h @@ -58,6 +58,8 @@ public: bool reloadServerScript(QUuid entityID); MessageID getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback); + void callEntityServerMethod(QUuid id, const QString& method, const QStringList& params); + private slots: void handleNodeKilled(SharedNodePointer node); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index ea65f8ac78..9e2eb51fdd 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -123,6 +123,7 @@ public: ReplicatedBulkAvatarData, OctreeFileReplacementFromUrl, ChallengeOwnership, + EntityScriptCallMethod, NUM_PACKET_TYPE };