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 | 12 | #include "EntityScriptServer.h" |
| 13 | 13 | |
| 14 | +#include <AudioConstants.h> | |
| 14 | 15 | #include <AudioInjectorManager.h> |
| 15 | 16 | #include <EntityScriptingInterface.h> |
| 16 | 17 | #include <MessagesClient.h> |
| @@ -20,15 +21,13 @@ · 3 unmodified lines | ||
| 20 | 21 | #include <ScriptCache.h> |
| 21 | 22 | #include <ScriptEngines.h> |
| 22 | 23 | #include <SoundCache.h> |
| 24 | +#include <WebSocketServerClass.h> | |
| 23 | 25 | |
| 24 | 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) : | |
| 29 | − ThreadedAssignment(message), | |
| 30 | − _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) | |
| 31 | −{ | |
| 30 | +EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) { | |
| 32 | 31 | DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender); |
| 33 | 32 | |
| 34 | 33 | ResourceManager::init(); |
| @@ -44,14 +43,15 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : · 9 unmodified lines | ||
| 44 | 43 | |
| 45 | 44 | |
| 46 | 45 | auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver(); |
| 47 | − | |
| 48 | − packetReceiver.registerListenerForTypes({ PacketType::MixedAudio, PacketType::SilentAudioFrame }, | |
| 49 | − this, "handleAudioPacket"); | |
| 50 | 46 | packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, |
| 51 | 47 | this, "handleOctreePacket"); |
| 52 | 48 | packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); |
| 53 | 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 | 57 | static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server"; |
| @@ -77,6 +77,27 @@ void EntityScriptServer::run() { · 19 unmodified lines | ||
| 77 | 77 | nodeList->addSetOfNodeTypesToNodeInterestSet({ |
| 78 | 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 | 103 | void EntityScriptServer::nodeActivated(SharedNodePointer activatedNode) { |
| @@ -121,13 +142,11 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) { · 38 unmodified lines | ||
| 121 | 142 | _encoder = nullptr; |
| 122 | 143 | _codec = nullptr; |
| 123 | 144 | } |
| 124 | − _receivedAudioStream.cleanupCodec(); | |
| 125 | 145 | |
| 126 | 146 | auto codecPlugins = PluginManager::getInstance()->getCodecPlugins(); |
| 127 | 147 | for (auto& plugin : codecPlugins) { |
| 128 | 148 | if (_selectedCodecName == plugin->getName()) { |
| 129 | 149 | _codec = plugin; |
| 130 | − _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); | |
| 131 | 150 | _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO); |
| 132 | 151 | qDebug() << "Selected Codec Plugin:" << _codec.get(); |
| 133 | 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) { | |
| 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 | + } | |
| 140 | 202 | |
| 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 | + } | |
| 143 | 242 | } |
| 144 | 243 | |
| 145 | 244 | void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { |
| @@ -151,11 +250,43 @@ void EntityScriptServer::sendStatsPacket() { · 5 unmodified lines | ||
| 151 | 250 | } |
| 152 | 251 | |
| 153 | 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 | 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 | 292 | void EntityScriptServer::aboutToFinish() { |