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
1111
1212 #include "EntityScriptServer.h"
1313
14+#include <AudioConstants.h>
1415 #include <AudioInjectorManager.h>
1516 #include <EntityScriptingInterface.h>
1617 #include <MessagesClient.h>
@@ -20,15 +21,13 @@ · 3 unmodified lines
2021 #include <ScriptCache.h>
2122 #include <ScriptEngines.h>
2223 #include <SoundCache.h>
24+#include <WebSocketServerClass.h>
2325
2426 #include "../entities/AssignmentParentFinder.h"
2527
26−static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
28+int EntityScriptServer::_entitiesScriptEngineCount = 0;
2729
28−EntityScriptServer::EntityScriptServer(ReceivedMessage& message) :
29− ThreadedAssignment(message),
30− _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES)
31−{
30+EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) {
3231 DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
3332
3433 ResourceManager::init();
@@ -44,14 +43,15 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : · 9 unmodified lines
4443
4544
4645 auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
47−
48− packetReceiver.registerListenerForTypes({ PacketType::MixedAudio, PacketType::SilentAudioFrame },
49− this, "handleAudioPacket");
5046 packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
5147 this, "handleOctreePacket");
5248 packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket");
5349 packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat");
5450
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");
5555 }
5656
5757 static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server";
@@ -77,6 +77,27 @@ void EntityScriptServer::run() { · 19 unmodified lines
7777 nodeList->addSetOfNodeTypesToNodeInterestSet({
7878 NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
7979 });
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);
80101 }
81102
82103 void EntityScriptServer::nodeActivated(SharedNodePointer activatedNode) {
@@ -121,13 +142,11 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) { · 38 unmodified lines
121142 _encoder = nullptr;
122143 _codec = nullptr;
123144 }
124− _receivedAudioStream.cleanupCodec();
125145
126146 auto codecPlugins = PluginManager::getInstance()->getCodecPlugins();
127147 for (auto& plugin : codecPlugins) {
128148 if (_selectedCodecName == plugin->getName()) {
129149 _codec = plugin;
130− _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO);
131150 _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO);
132151 qDebug() << "Selected Codec Plugin:" << _codec.get();
133152 break;
@@ -135,11 +154,91 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) { · 1 unmodified line
135154 }
136155 }
137156
138−void EntityScriptServer::handleAudioPacket(QSharedPointer<ReceivedMessage> message) {
139− _receivedAudioStream.parseData(*message);
157+void EntityScriptServer::resetEntitiesScriptEngine() {
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+
190+void 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+ }
140202
141− _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness();
142− _receivedAudioStream.clearBuffer();
203+ _entityViewer.clear();
204+}
205+
206+void 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+
215+void EntityScriptServer::addingEntity(const EntityItemID& entityID) {
216+ checkAndCallPreload(entityID);
217+}
218+
219+void EntityScriptServer::deletingEntity(const EntityItemID& entityID) {
220+ if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) {
221+ _entitiesScriptEngine->unloadEntityScript(entityID);
222+ }
223+}
224+
225+void EntityScriptServer::entitySciptChanging(const EntityItemID& entityID, const bool reload) {
226+ if (_entityViewer.getTree() && !_shuttingDown) {
227+ _entitiesScriptEngine->unloadEntityScript(entityID);
228+ checkAndCallPreload(entityID, reload);
229+ }
230+}
231+
232+void 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+ }
143242 }
144243
145244 void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) {
@@ -151,11 +250,43 @@ void EntityScriptServer::sendStatsPacket() { · 5 unmodified lines
151250 }
152251
153252 void 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);
154264
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+ }
155279 }
156280
157281 void EntityScriptServer::handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
282+ NodeType_t nodeType;
283+ message->peekPrimitive(&nodeType);
158284
285+ // PacketType_JURISDICTION, first byte is the node type...
286+ if (nodeType == NodeType::EntityServer) {
287+ DependencyManager::get<EntityScriptingInterface>()->getJurisdictionListener()->
288+ queueReceivedPacket(message, senderNode);
289+ }
159290 }
160291
161292 void EntityScriptServer::aboutToFinish() {