Merge pull request #11664 from ZappoMan/callEntityClientMethod

implement callEntityClientMethod
This commit is contained in:
Brad Hefta-Gaub 2017-10-24 14:43:39 -07:00 committed by GitHub
commit ecf8d35f5f
7 changed files with 117 additions and 5 deletions

View file

@ -30,6 +30,8 @@
#include <UUID.h>
#include <WebSocketServerClass.h>
#include <EntityScriptClient.h> // for EntityScriptServerServices
#include "EntityScriptServerLogging.h"
#include "../entities/AssignmentParentFinder.h"
@ -68,6 +70,9 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
DependencyManager::set<ScriptCache>();
DependencyManager::set<ScriptEngines>(ScriptEngine::ENTITY_SERVER_SCRIPT);
DependencyManager::set<EntityScriptServerServices>();
// Needed to ensure the creation of the DebugDraw instance on the main thread
DebugDraw::getInstance();
@ -583,6 +588,7 @@ void EntityScriptServer::aboutToFinish() {
// cleanup the AudioInjectorManager (and any still running injectors)
DependencyManager::destroy<AudioInjectorManager>();
DependencyManager::destroy<ScriptEngines>();
DependencyManager::destroy<EntityScriptServerServices>();
// cleanup codec & encoder
if (_codec && _encoder) {

View file

@ -50,6 +50,10 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership
connect(nodeList.data(), &NodeList::canRezCertifiedChanged, this, &EntityScriptingInterface::canRezCertifiedChanged);
connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged);
connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged);
auto& packetReceiver = nodeList->getPacketReceiver();
packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket");
}
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
@ -571,6 +575,48 @@ void EntityScriptingInterface::callEntityServerMethod(QUuid id, const QString& m
DependencyManager::get<EntityScriptClient>()->callEntityServerMethod(id, method, params);
}
void EntityScriptingInterface::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) {
PROFILE_RANGE(script_entities, __FUNCTION__);
auto scriptServerServices = DependencyManager::get<EntityScriptServerServices>();
// this won't be available on clients
if (scriptServerServices) {
scriptServerServices->callEntityClientMethod(clientSessionID, entityID, method, params);
} else {
qWarning() << "Entities.callEntityClientMethod() not allowed in client";
}
}
void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode) {
PROFILE_RANGE(script_entities, __FUNCTION__);
auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer);
if (entityScriptServer == senderNode) {
auto entityID = QUuid::fromRfc4122(receivedMessage->read(NUM_BYTES_RFC4122_UUID));
auto method = receivedMessage->readString();
quint16 paramCount;
receivedMessage->readPrimitive(&paramCount);
QStringList params;
for (int param = 0; param < paramCount; param++) {
auto paramString = receivedMessage->readString();
params << paramString;
}
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, method, params, senderNode->getUUID());
}
}
}
QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
PROFILE_RANGE(script_entities, __FUNCTION__);

View file

@ -189,12 +189,15 @@ public slots:
Q_INVOKABLE void deleteEntity(QUuid entityID);
/**jsdoc
* 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)
* Call a method on an entity in the same context as this function is called. 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.
* using `params` as the list of arguments. If this is called within an entity script, the
* method will be executed on the client in the entity script engine in which it was called. If
* this is called in an entity server script, the method will be executed on the entity server
* script engine.
*
* @function Entities.callEntityMethod
* @param {EntityID} entityID The ID of the entity to call the method on.
@ -218,6 +221,21 @@ public slots:
*/
Q_INVOKABLE void callEntityServerMethod(QUuid entityID, const QString& method, const QStringList& params = QStringList());
/**jsdoc
* Call a client method on an entity on a specific client node. Allows a server entity script to call a
* method on an entity's client script for a particular client. The method will execute in the entity script
* engine on that single client. If the entity does not have an entity script or the method does not exist, or
* the client is not connected to the domain, or you attempt to make this call outside of the entity server
* script, this call will have no effect.
*
* @function Entities.callEntityClientMethod
* @param {SessionID} clientSessionID The session ID of the client to call the method on.
* @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 callEntityClientMethod(QUuid clientSessionID, 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
@ -447,6 +465,10 @@ protected:
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
function(_entitiesScriptEngine);
};
private slots:
void handleEntityScriptCallMethodPacket(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode);
private:
bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulationPointer, EntityItemPointer)> actor);
bool polyVoxWorker(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor);

View file

@ -92,6 +92,28 @@ void EntityScriptClient::callEntityServerMethod(QUuid entityID, const QString& m
}
}
void EntityScriptServerServices::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) {
// only valid to call this function if you are the entity script server
auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer targetClient = nodeList->nodeWithUUID(clientSessionID);
if (nodeList->getOwnerType() == NodeType::EntityScriptServer && targetClient) {
auto packetList = NLPacketList::create(PacketType::EntityScriptCallMethod, QByteArray(), true, true);
packetList->write(entityID.toRfc4122());
packetList->writeString(method);
quint16 paramCount = params.length();
packetList->writePrimitive(paramCount);
foreach(const QString& param, params) {
packetList->writeString(param);
}
nodeList->sendPacketList(std::move(packetList), *targetClient);
}
}
MessageID EntityScriptClient::getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback) {
auto nodeList = DependencyManager::get<NodeList>();

View file

@ -74,4 +74,11 @@ private:
void forceFailureOfPendingRequests(SharedNodePointer node);
};
class EntityScriptServerServices : public QObject, public Dependency {
Q_OBJECT
public:
void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params);
};
#endif

View file

@ -62,6 +62,9 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::DomainServerAddedNode:
return static_cast<PacketVersion>(DomainServerAddedNodeVersion::PermissionsGrid);
case PacketType::EntityScriptCallMethod:
return static_cast<PacketVersion>(EntityScriptCallMethodVersion::ClientCallable);
case PacketType::MixedAudio:
case PacketType::SilentAudioFrame:
case PacketType::InjectAudio:

View file

@ -274,6 +274,12 @@ const PacketVersion VERSION_ENTITIES_UV_MODE_PROPERTY = 76;
const PacketVersion VERSION_ENTITIES_STROKE_COLOR_PROPERTY = 77;
enum class EntityScriptCallMethodVersion : PacketVersion {
ServerCallable = 18,
ClientCallable = 19
};
enum class EntityQueryPacketVersion: PacketVersion {
JSONFilter = 18,
JSONFilterWithFamilyTree = 19