Showing the changes to assignment-client/src/scripts/EntityScriptServer.cpp (1 of 5 files). Show all
Unified · Split
| @@ -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 | ||
| 26 | static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; | 28 | int EntityScriptServer::_entitiesScriptEngineCount = 0; |
| 27 | 29 | ||
| 28 | EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : | 30 | EntityScriptServer::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 | ||
| 57 | static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server"; | 57 | static 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::AssetServer | 78 | 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 | ||
| 82 | void EntityScriptServer::nodeActivated(SharedNodePointer activatedNode) { | 103 | void 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 | ||
| 138 | void EntityScriptServer::handleAudioPacket(QSharedPointer<ReceivedMessage> message) { | 157 | void 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 | |||
| 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 | } | ||
| 140 | 202 | ||
| 141 | _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness(); | 203 | _entityViewer.clear(); |
| 142 | _receivedAudioStream.clearBuffer(); | 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 | } | ||
| 143 | } | 242 | } |
| 144 | 243 | ||
| 145 | void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { | 244 | void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { |
| @@ -151,11 +250,43 @@ void EntityScriptServer::sendStatsPacket() { · 5 unmodified lines | |||
| 151 | } | 250 | } |
| 152 | 251 | ||
| 153 | void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) { | 252 | 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); | ||
| 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 | ||
| 157 | void EntityScriptServer::handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) { | 281 | void 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 | ||
| 161 | void EntityScriptServer::aboutToFinish() { | 292 | void EntityScriptServer::aboutToFinish() { |