History

More entity script server work

Atlante45 committed 9 years ago

Commit 5db37ff1 parent 529286b5 files · +190 −72Browse files

Showing the changes to assignment-client/src/scripts/EntityScriptServer.cpp (1 of 5 files). Show all

Unified · Split

assignment-client/src/scripts/EntityScriptServer.cpp+145−14
@@ -11,6 +11,7 @@ · 10 unmodified lines
11 11
12#include "EntityScriptServer.h"12#include "EntityScriptServer.h"
13 13
14#include <AudioConstants.h>
14#include <AudioInjectorManager.h>15#include <AudioInjectorManager.h>
15#include <EntityScriptingInterface.h>16#include <EntityScriptingInterface.h>
16#include <MessagesClient.h>17#include <MessagesClient.h>
@@ -20,15 +21,13 @@ · 3 unmodified lines
20#include <ScriptCache.h>21#include <ScriptCache.h>
21#include <ScriptEngines.h>22#include <ScriptEngines.h>
22#include <SoundCache.h>23#include <SoundCache.h>
24#include <WebSocketServerClass.h>
23 25
24#include "../entities/AssignmentParentFinder.h"26#include "../entities/AssignmentParentFinder.h"
25 27
26static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;28int EntityScriptServer::_entitiesScriptEngineCount = 0;
27 29
28EntityScriptServer::EntityScriptServer(ReceivedMessage& message) :30EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) {
29 ThreadedAssignment(message),
30 _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES)
31{
32 DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);31 DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
33 32
34 ResourceManager::init();33 ResourceManager::init();
@@ -44,14 +43,15 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : · 9 unmodified lines
44 43
45 44
46 auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();45 auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
47
48 packetReceiver.registerListenerForTypes({ PacketType::MixedAudio, PacketType::SilentAudioFrame },
49 this, "handleAudioPacket");
50 packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },46 packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
51 this, "handleOctreePacket");47 this, "handleOctreePacket");
52 packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket");48 packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket");
53 packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat");49 packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat");
54 50
51 auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
52 packetReceiver.registerListener(PacketType::BulkAvatarData, avatarHashMap.data(), "processAvatarDataPacket");
53 packetReceiver.registerListener(PacketType::KillAvatar, avatarHashMap.data(), "processKillAvatar");
54 packetReceiver.registerListener(PacketType::AvatarIdentity, avatarHashMap.data(), "processAvatarIdentityPacket");
55}55}
56 56
57static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server";57static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server";
@@ -77,6 +77,27 @@ void EntityScriptServer::run() { · 19 unmodified lines
77 nodeList->addSetOfNodeTypesToNodeInterestSet({77 nodeList->addSetOfNodeTypesToNodeInterestSet({
78 NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer78 NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
79 });79 });
80
81 // Setup Script Engine
82 resetEntitiesScriptEngine();
83
84 // we need to make sure that init has been called for our EntityScriptingInterface
85 // so that it actually has a jurisdiction listener when we ask it for it next
86 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
87 entityScriptingInterface->init();
88 _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener());
89
90 _entityViewer.init();
91
92 entityScriptingInterface->setEntityTree(_entityViewer.getTree());
93
94 DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
95
96
97 auto tree = _entityViewer.getTree().get();
98 connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection);
99 connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection);
100 connect(tree, &EntityTree::entityScriptChanging, this, &EntityScriptServer::entitySciptChanging, Qt::QueuedConnection);
80}101}
81 102
82void EntityScriptServer::nodeActivated(SharedNodePointer activatedNode) {103void EntityScriptServer::nodeActivated(SharedNodePointer activatedNode) {
@@ -121,13 +142,11 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) { · 38 unmodified lines
121 _encoder = nullptr;142 _encoder = nullptr;
122 _codec = nullptr;143 _codec = nullptr;
123 }144 }
124 _receivedAudioStream.cleanupCodec();
125 145
126 auto codecPlugins = PluginManager::getInstance()->getCodecPlugins();146 auto codecPlugins = PluginManager::getInstance()->getCodecPlugins();
127 for (auto& plugin : codecPlugins) {147 for (auto& plugin : codecPlugins) {
128 if (_selectedCodecName == plugin->getName()) {148 if (_selectedCodecName == plugin->getName()) {
129 _codec = plugin;149 _codec = plugin;
130 _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO);
131 _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO);150 _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO);
132 qDebug() << "Selected Codec Plugin:" << _codec.get();151 qDebug() << "Selected Codec Plugin:" << _codec.get();
133 break;152 break;
@@ -135,11 +154,91 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) { · 1 unmodified line
135 }154 }
136}155}
137 156
138void EntityScriptServer::handleAudioPacket(QSharedPointer<ReceivedMessage> message) {157void EntityScriptServer::resetEntitiesScriptEngine() {
139 _receivedAudioStream.parseData(*message);158 auto engineName = QString("Entities %1").arg(++_entitiesScriptEngineCount);
159 auto newEngine = QSharedPointer<ScriptEngine>(new ScriptEngine(NO_SCRIPT, engineName));
160
161 newEngine->registerGlobalObject("EntityViewer", &_entityViewer);
162
163 auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor);
164 newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
165
166
167// newEngine->setEmitScriptUpdatesFunction([this]() {
168// SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer);
169// return !entityServerNode || isPhysicsEnabled();
170// });
171
172 newEngine->registerGlobalObject("AvatarList", DependencyManager::get<AvatarHashMap>().data());
173 newEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
174
175 // connect this script engines printedMessage signal to the global ScriptEngines these various messages
176 auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
177 connect(newEngine.data(), &ScriptEngine::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage);
178 connect(newEngine.data(), &ScriptEngine::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage);
179 connect(newEngine.data(), &ScriptEngine::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage);
180 connect(newEngine.data(), &ScriptEngine::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage);
181
182
183 newEngine->runInThread();
184 DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngine.data());
185
186 _entitiesScriptEngine.swap(newEngine);
187}
188
189
190void EntityScriptServer::clear() {
191 // unload and stop the engine
192 if (_entitiesScriptEngine) {
193 // do this here (instead of in deleter) to avoid marshalling unload signals back to this thread
194 _entitiesScriptEngine->unloadAllEntityScripts();
195 _entitiesScriptEngine->stop();
196 }
197
198 // reset the engine
199 if (!_shuttingDown) {
200 resetEntitiesScriptEngine();
201 }
140 202
141 _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness();203 _entityViewer.clear();
142 _receivedAudioStream.clearBuffer();204}
205
206void EntityScriptServer::shutdown() {
207 if (_entitiesScriptEngine) {
208 _entitiesScriptEngine->disconnectNonEssentialSignals(); // disconnect all slots/signals from the script engine, except essential
209 }
210 _shuttingDown = true;
211
212 clear(); // always clear() on shutdown
213}
214
215void EntityScriptServer::addingEntity(const EntityItemID& entityID) {
216 checkAndCallPreload(entityID);
217}
218
219void EntityScriptServer::deletingEntity(const EntityItemID& entityID) {
220 if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) {
221 _entitiesScriptEngine->unloadEntityScript(entityID);
222 }
223}
224
225void EntityScriptServer::entitySciptChanging(const EntityItemID& entityID, const bool reload) {
226 if (_entityViewer.getTree() && !_shuttingDown) {
227 _entitiesScriptEngine->unloadEntityScript(entityID);
228 checkAndCallPreload(entityID, reload);
229 }
230}
231
232void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, const bool reload) {
233 if (_entityViewer.getTree() && !_shuttingDown) {
234 EntityItemPointer entity = _entityViewer.getTree()->findEntityByEntityItemID(entityID);
235 if (entity && entity->shouldPreloadScript() && _entitiesScriptEngine) {
236 QString scriptUrl = entity->getScript();
237 scriptUrl = ResourceManager::normalizeURL(scriptUrl);
238 ScriptEngine::loadEntityScript(_entitiesScriptEngine, entityID, scriptUrl, reload);
239 entity->scriptHasPreloaded();
240 }
241 }
143}242}
144 243
145void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) {244void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) {
@@ -151,11 +250,43 @@ void EntityScriptServer::sendStatsPacket() { · 5 unmodified lines
151}250}
152 251
153void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {252void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
253 auto packetType = message->getType();
254
255 if (packetType == PacketType::OctreeStats) {
256
257 int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(message, senderNode);
258 if (message->getSize() > statsMessageLength) {
259 // pull out the piggybacked packet and create a new QSharedPointer<NLPacket> for it
260 int piggyBackedSizeWithHeader = message->getSize() - statsMessageLength;
261
262 auto buffer = std::unique_ptr<char[]>(new char[piggyBackedSizeWithHeader]);
263 memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggyBackedSizeWithHeader);
154 264
265 auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, message->getSenderSockAddr());
266 message = QSharedPointer<ReceivedMessage>::create(*newPacket);
267 } else {
268 return; // bail since no piggyback data
269 }
270
271 packetType = message->getType();
272 } // fall through to piggyback message
273
274 if (packetType == PacketType::EntityData) {
275 _entityViewer.processDatagram(*message, senderNode);
276 } else if (packetType == PacketType::EntityErase) {
277 _entityViewer.processEraseMessage(*message, senderNode);
278 }
155}279}
156 280
157void EntityScriptServer::handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {281void EntityScriptServer::handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
282 NodeType_t nodeType;
283 message->peekPrimitive(&nodeType);
158 284
285 // PacketType_JURISDICTION, first byte is the node type...
286 if (nodeType == NodeType::EntityServer) {
287 DependencyManager::get<EntityScriptingInterface>()->getJurisdictionListener()->
288 queueReceivedPacket(message, senderNode);
289 }
159}290}
160 291
161void EntityScriptServer::aboutToFinish() {292void EntityScriptServer::aboutToFinish() {