mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 14:08:51 +02:00
Add support for sending requests to entity script server
This commit is contained in:
parent
340eeb94fa
commit
8137c59ef7
6 changed files with 261 additions and 3 deletions
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "../entities/AssignmentParentFinder.h"
|
#include "../entities/AssignmentParentFinder.h"
|
||||||
|
|
||||||
|
const size_t UUID_LENGTH_BYTES = 16;
|
||||||
|
|
||||||
int EntityScriptServer::_entitiesScriptEngineCount = 0;
|
int EntityScriptServer::_entitiesScriptEngineCount = 0;
|
||||||
|
|
||||||
EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) {
|
EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) {
|
||||||
|
@ -52,10 +54,39 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
||||||
packetReceiver.registerListener(PacketType::BulkAvatarData, avatarHashMap.data(), "processAvatarDataPacket");
|
packetReceiver.registerListener(PacketType::BulkAvatarData, avatarHashMap.data(), "processAvatarDataPacket");
|
||||||
packetReceiver.registerListener(PacketType::KillAvatar, avatarHashMap.data(), "processKillAvatar");
|
packetReceiver.registerListener(PacketType::KillAvatar, avatarHashMap.data(), "processKillAvatar");
|
||||||
packetReceiver.registerListener(PacketType::AvatarIdentity, avatarHashMap.data(), "processAvatarIdentityPacket");
|
packetReceiver.registerListener(PacketType::AvatarIdentity, avatarHashMap.data(), "processAvatarIdentityPacket");
|
||||||
|
|
||||||
|
packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket");
|
||||||
|
packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server";
|
static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server";
|
||||||
|
|
||||||
|
void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||||
|
auto entityID = QUuid::fromRfc4122(message->read(UUID_LENGTH_BYTES));
|
||||||
|
|
||||||
|
if (_entityViewer.getTree() && !_shuttingDown) {
|
||||||
|
qDebug() << "Reloading: " << entityID;
|
||||||
|
_entitiesScriptEngine->unloadEntityScript(entityID);
|
||||||
|
checkAndCallPreload(entityID, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityScriptServer::handleEntityScriptGetStatusPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||||
|
MessageID messageID;
|
||||||
|
message->readPrimitive(&messageID);
|
||||||
|
auto entityID = QUuid::fromRfc4122(message->read(UUID_LENGTH_BYTES));
|
||||||
|
|
||||||
|
// TODO(Huffman) Get Status
|
||||||
|
|
||||||
|
qDebug() << "Getting script status of: " << entityID;
|
||||||
|
auto replyPacket = NLPacket::create(PacketType::EntityScriptGetStatusReply, -1, true);
|
||||||
|
replyPacket->writePrimitive(messageID);
|
||||||
|
replyPacket->writeString("running");
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
nodeList->sendPacket(std::move(replyPacket), *senderNode);
|
||||||
|
}
|
||||||
|
|
||||||
void EntityScriptServer::run() {
|
void EntityScriptServer::run() {
|
||||||
// make sure we request our script once the agent connects to the domain
|
// make sure we request our script once the agent connects to the domain
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
@ -75,7 +106,8 @@ void EntityScriptServer::run() {
|
||||||
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &EntityScriptServer::nodeKilled);
|
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &EntityScriptServer::nodeKilled);
|
||||||
|
|
||||||
nodeList->addSetOfNodeTypesToNodeInterestSet({
|
nodeList->addSetOfNodeTypesToNodeInterestSet({
|
||||||
NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
|
NodeType::Agent, NodeType::AudioMixer, NodeType::AvatarMixer,
|
||||||
|
NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup Script Engine
|
// Setup Script Engine
|
||||||
|
|
|
@ -39,6 +39,9 @@ private slots:
|
||||||
void handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
void handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||||
void handleSelectedAudioFormat(QSharedPointer<ReceivedMessage> message);
|
void handleSelectedAudioFormat(QSharedPointer<ReceivedMessage> message);
|
||||||
|
|
||||||
|
void handleReloadEntityServerScriptPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||||
|
void handleEntityScriptGetStatusPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void negotiateAudioFormat();
|
void negotiateAudioFormat();
|
||||||
void selectAudioFormat(const QString& selectedCodecName);
|
void selectAudioFormat(const QString& selectedCodecName);
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
#include <CursorManager.h>
|
#include <CursorManager.h>
|
||||||
#include <DebugDraw.h>
|
#include <DebugDraw.h>
|
||||||
#include <DeferredLightingEffect.h>
|
#include <DeferredLightingEffect.h>
|
||||||
#include <display-plugins/DisplayPlugin.h>
|
#include <EntityScriptClient.h>
|
||||||
#include <EntityScriptingInterface.h>
|
#include <EntityScriptingInterface.h>
|
||||||
#include <ErrorDialog.h>
|
#include <ErrorDialog.h>
|
||||||
#include <FileScriptingInterface.h>
|
#include <FileScriptingInterface.h>
|
||||||
|
@ -173,6 +173,7 @@
|
||||||
#include "FrameTimingsScriptingInterface.h"
|
#include "FrameTimingsScriptingInterface.h"
|
||||||
#include <GPUIdent.h>
|
#include <GPUIdent.h>
|
||||||
#include <gl/GLHelpers.h>
|
#include <gl/GLHelpers.h>
|
||||||
|
#include <EntityScriptClient.h>
|
||||||
|
|
||||||
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||||
// FIXME seems to be broken.
|
// FIXME seems to be broken.
|
||||||
|
@ -514,6 +515,7 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
DependencyManager::set<EntityTreeRenderer>(true, qApp, qApp);
|
DependencyManager::set<EntityTreeRenderer>(true, qApp, qApp);
|
||||||
DependencyManager::set<CompositorHelper>();
|
DependencyManager::set<CompositorHelper>();
|
||||||
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
||||||
|
DependencyManager::set<EntityScriptClient>();
|
||||||
return previousSessionCrashed;
|
return previousSessionCrashed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,7 +854,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
|
|
||||||
// tell the NodeList instance who to tell the domain server we care about
|
// tell the NodeList instance who to tell the domain server we care about
|
||||||
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
|
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
|
||||||
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer);
|
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer << NodeType::EntityScriptServer);
|
||||||
|
|
||||||
// connect to the packet sent signal of the _entityEditSender
|
// connect to the packet sent signal of the _entityEditSender
|
||||||
connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
|
connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "QVariantGLM.h"
|
#include "QVariantGLM.h"
|
||||||
#include "SimulationOwner.h"
|
#include "SimulationOwner.h"
|
||||||
#include "ZoneEntityItem.h"
|
#include "ZoneEntityItem.h"
|
||||||
|
#include <EntityScriptClient.h>
|
||||||
|
|
||||||
|
|
||||||
EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :
|
EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :
|
||||||
|
|
153
libraries/networking/src/EntityScriptClient.cpp
Normal file
153
libraries/networking/src/EntityScriptClient.cpp
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
#include "EntityScriptClient.h"
|
||||||
|
#include "NodeList.h"
|
||||||
|
#include "NetworkLogging.h"
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
MessageID EntityScriptClient::_currentID = 0;
|
||||||
|
|
||||||
|
GetScriptStatusRequest::GetScriptStatusRequest(QUuid entityID) : _entityID(entityID) {
|
||||||
|
}
|
||||||
|
|
||||||
|
GetScriptStatusRequest::~GetScriptStatusRequest() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetScriptStatusRequest::start() {
|
||||||
|
auto client = DependencyManager::get<EntityScriptClient>();
|
||||||
|
qDebug() << "Sending script status request";
|
||||||
|
client->getEntityServerScriptStatus(_entityID, [this](bool responseReceived) {
|
||||||
|
qDebug() << "Received script status request";
|
||||||
|
emit finished(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityScriptClient::EntityScriptClient() {
|
||||||
|
setCustomDeleter([](Dependency* dependency){
|
||||||
|
static_cast<EntityScriptClient*>(dependency)->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||||
|
|
||||||
|
packetReceiver.registerListener(PacketType::EntityScriptGetStatusReply, this, "handleGetScriptStatusReply");
|
||||||
|
|
||||||
|
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &EntityScriptClient::handleNodeKilled);
|
||||||
|
connect(nodeList.data(), &LimitedNodeList::clientConnectionToNodeReset,
|
||||||
|
this, &EntityScriptClient::handleNodeClientConnectionReset);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetScriptStatusRequest* EntityScriptClient::createScriptStatusRequest(QUuid entityID) {
|
||||||
|
auto request = new GetScriptStatusRequest(entityID);
|
||||||
|
|
||||||
|
request->moveToThread(thread());
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityScriptClient::reloadServerScript(QUuid entityID) {
|
||||||
|
// Send packet to entity script server
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer);
|
||||||
|
|
||||||
|
if (entityScriptServer) {
|
||||||
|
auto id = entityID.toRfc4122();
|
||||||
|
auto payloadSize = id.size();
|
||||||
|
auto packet = NLPacket::create(PacketType::ReloadEntityServerScript, payloadSize, true);
|
||||||
|
|
||||||
|
packet->write(id);
|
||||||
|
|
||||||
|
if (nodeList->sendPacket(std::move(packet), *entityScriptServer) != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageID EntityScriptClient::getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback) {
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer);
|
||||||
|
|
||||||
|
if (entityScriptServer) {
|
||||||
|
auto packetList = NLPacketList::create(PacketType::EntityScriptGetStatus, QByteArray(), true, true);
|
||||||
|
|
||||||
|
auto messageID = ++_currentID;
|
||||||
|
packetList->writePrimitive(messageID);
|
||||||
|
|
||||||
|
packetList->write(entityID.toRfc4122());
|
||||||
|
|
||||||
|
if (nodeList->sendPacketList(std::move(packetList), *entityScriptServer) != -1) {
|
||||||
|
_pendingEntityScriptStatusRequests[entityScriptServer][messageID] = callback;
|
||||||
|
|
||||||
|
return messageID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(false);
|
||||||
|
return INVALID_MESSAGE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityScriptClient::handleGetScriptStatusReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||||
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
|
|
||||||
|
MessageID messageID;
|
||||||
|
message->readPrimitive(&messageID);
|
||||||
|
|
||||||
|
auto status = message->readString();
|
||||||
|
|
||||||
|
// Check if we have any pending requests for this node
|
||||||
|
auto messageMapIt = _pendingEntityScriptStatusRequests.find(senderNode);
|
||||||
|
if (messageMapIt != _pendingEntityScriptStatusRequests.end()) {
|
||||||
|
|
||||||
|
// Found the node, get the MessageID -> Callback map
|
||||||
|
auto& messageCallbackMap = messageMapIt->second;
|
||||||
|
|
||||||
|
// Check if we have this pending request
|
||||||
|
auto requestIt = messageCallbackMap.find(messageID);
|
||||||
|
if (requestIt != messageCallbackMap.end()) {
|
||||||
|
auto callback = requestIt->second;
|
||||||
|
callback(true);
|
||||||
|
messageCallbackMap.erase(requestIt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from
|
||||||
|
// it to avoid constantly creating/deleting the map on subsequent requests.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityScriptClient::handleNodeKilled(SharedNodePointer node) {
|
||||||
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
|
|
||||||
|
if (node->getType() != NodeType::EntityScriptServer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceFailureOfPendingRequests(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityScriptClient::handleNodeClientConnectionReset(SharedNodePointer node) {
|
||||||
|
// a client connection to a Node was reset
|
||||||
|
// if it was an EntityScriptServer we need to cause anything pending to fail so it is re-attempted
|
||||||
|
|
||||||
|
if (node->getType() != NodeType::EntityScriptServer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//qCDebug(entity_script_client) << "EntityScriptClient detected client connection reset handshake with Asset Server - failing any pending requests";
|
||||||
|
|
||||||
|
forceFailureOfPendingRequests(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityScriptClient::forceFailureOfPendingRequests(SharedNodePointer node) {
|
||||||
|
|
||||||
|
{
|
||||||
|
auto messageMapIt = _pendingEntityScriptStatusRequests.find(node);
|
||||||
|
if (messageMapIt != _pendingEntityScriptStatusRequests.end()) {
|
||||||
|
for (const auto& value : messageMapIt->second) {
|
||||||
|
value.second(false);
|
||||||
|
}
|
||||||
|
messageMapIt->second.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
libraries/networking/src/EntityScriptClient.h
Normal file
67
libraries/networking/src/EntityScriptClient.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
//
|
||||||
|
// EntityScriptClient.h
|
||||||
|
// libraries/networking/src
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 2017/01/13
|
||||||
|
// 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_EntityScriptClient_h
|
||||||
|
#define hifi_EntityScriptClient_h
|
||||||
|
|
||||||
|
#include "LimitedNodeList.h"
|
||||||
|
#include "ReceivedMessage.h"
|
||||||
|
#include "AssetUtils.h"
|
||||||
|
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
using MessageID = uint32_t;
|
||||||
|
|
||||||
|
using GetScriptStatusCallback = std::function<void(bool responseReceived)>;
|
||||||
|
|
||||||
|
class GetScriptStatusRequest : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
GetScriptStatusRequest(QUuid);
|
||||||
|
~GetScriptStatusRequest();
|
||||||
|
|
||||||
|
Q_INVOKABLE void start();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished(GetScriptStatusRequest* request);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QUuid _entityID;
|
||||||
|
MessageID _messageID;
|
||||||
|
QString status;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EntityScriptClient : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
EntityScriptClient();
|
||||||
|
|
||||||
|
Q_INVOKABLE GetScriptStatusRequest* createScriptStatusRequest(QUuid entityID);
|
||||||
|
|
||||||
|
bool reloadServerScript(QUuid entityID);
|
||||||
|
MessageID getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleNodeKilled(SharedNodePointer node);
|
||||||
|
void handleNodeClientConnectionReset(SharedNodePointer node);
|
||||||
|
|
||||||
|
void handleGetScriptStatusReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static MessageID _currentID;
|
||||||
|
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, GetScriptStatusCallback>> _pendingEntityScriptStatusRequests;
|
||||||
|
|
||||||
|
void forceFailureOfPendingRequests(SharedNodePointer node);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue