mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01: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"
|
||||
|
||||
const size_t UUID_LENGTH_BYTES = 16;
|
||||
|
||||
int EntityScriptServer::_entitiesScriptEngineCount = 0;
|
||||
|
||||
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::KillAvatar, avatarHashMap.data(), "processKillAvatar");
|
||||
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";
|
||||
|
||||
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() {
|
||||
// make sure we request our script once the agent connects to the domain
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
@ -75,7 +106,8 @@ void EntityScriptServer::run() {
|
|||
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &EntityScriptServer::nodeKilled);
|
||||
|
||||
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
|
||||
|
|
|
@ -39,6 +39,9 @@ private slots:
|
|||
void handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleSelectedAudioFormat(QSharedPointer<ReceivedMessage> message);
|
||||
|
||||
void handleReloadEntityServerScriptPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleEntityScriptGetStatusPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
|
||||
private:
|
||||
void negotiateAudioFormat();
|
||||
void selectAudioFormat(const QString& selectedCodecName);
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
#include <CursorManager.h>
|
||||
#include <DebugDraw.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
#include <EntityScriptClient.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
#include <ErrorDialog.h>
|
||||
#include <FileScriptingInterface.h>
|
||||
|
@ -173,6 +173,7 @@
|
|||
#include "FrameTimingsScriptingInterface.h"
|
||||
#include <GPUIdent.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <EntityScriptClient.h>
|
||||
|
||||
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||
// FIXME seems to be broken.
|
||||
|
@ -514,6 +515,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::set<EntityTreeRenderer>(true, qApp, qApp);
|
||||
DependencyManager::set<CompositorHelper>();
|
||||
DependencyManager::set<OffscreenQmlSurfaceCache>();
|
||||
DependencyManager::set<EntityScriptClient>();
|
||||
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
|
||||
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(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "QVariantGLM.h"
|
||||
#include "SimulationOwner.h"
|
||||
#include "ZoneEntityItem.h"
|
||||
#include <EntityScriptClient.h>
|
||||
|
||||
|
||||
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