diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 0f721ac98c..e2f0449216 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -28,7 +28,7 @@ void ScriptableAvatar::startAnimation(const QString& url, float fps, float prior Q_ARG(float, lastFrame), Q_ARG(const QStringList&, maskedJoints)); return; } - _animation = _scriptEngine->getAnimationCache()->getAnimation(url); + _animation = DependencyManager::get()->getAnimation(url); _animationDetails = AnimationDetails("", QUrl(url), fps, 0, loop, hold, false, firstFrame, lastFrame, true, firstFrame); _maskedJoints = maskedJoints; } diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 50de26c518..ae6f116537 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -76,6 +76,33 @@ } ] }, + { + "name": "scripts", + "label": "Scripts", + "settings": [ + { + "name": "persistent_scripts", + "type": "table", + "label": "Persistent Scripts", + "help": "Add the URLs for scripts that you would like to ensure are always running in your domain.", + "columns": [ + { + "name": "url", + "label": "Script URL" + }, + { + "name": "num_instances", + "label": "# instances", + "default": 1 + }, + { + "name": "pool", + "label": "Pool" + } + ] + } + ] + }, { "name": "audio_env", "label": "Audio Environment", diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index a27965abce..141bd72a26 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -363,7 +363,8 @@ function makeTableInputs(setting) { _.each(setting.columns, function(col) { html += "\ - \ + \ " }) @@ -389,8 +390,9 @@ function badgeSidebarForDifferences(changedElement) { // badge for any settings we have that are not the same or are not present in initialValues for (var setting in panelJSON) { - if (!_.isEqual(panelJSON[setting], initialPanelJSON[setting]) - && (panelJSON[setting] !== "" || _.has(initialPanelJSON, setting))) { + if ((!_.has(initialPanelJSON, setting) && panelJSON[setting] !== "") || + (!_.isEqual(panelJSON[setting], initialPanelJSON[setting]) + && (panelJSON[setting] !== "" || _.has(initialPanelJSON, setting)))) { badgeValue += 1 } } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index bf9505671b..470b69be01 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -233,6 +233,9 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { parseAssignmentConfigs(parsedTypes); populateDefaultStaticAssignmentsExcludingTypes(parsedTypes); + + // check for scripts the user wants to persist from their domain-server config + populateStaticScriptedAssignmentsFromSettings(); LimitedNodeList* nodeList = LimitedNodeList::createInstance(domainServerPort, domainServerDTLSPort); @@ -451,8 +454,6 @@ void DomainServer::parseAssignmentConfigs(QSet& excludedTypes) if (assignmentType != Assignment::AgentType) { createStaticAssignmentsForType(assignmentType, assignmentList); - } else { - createScriptedAssignmentsFromList(assignmentList); } excludedTypes.insert(assignmentType); @@ -468,35 +469,37 @@ void DomainServer::addStaticAssignmentToAssignmentHash(Assignment* newAssignment _allAssignments.insert(newAssignment->getUUID(), SharedAssignmentPointer(newAssignment)); } -void DomainServer::createScriptedAssignmentsFromList(const QVariantList &configList) { - foreach(const QVariant& configVariant, configList) { - if (configVariant.canConvert(QMetaType::QVariantMap)) { - QVariantMap configMap = configVariant.toMap(); - - // make sure we were passed a URL, otherwise this is an invalid scripted assignment - const QString ASSIGNMENT_URL_KEY = "url"; - QString assignmentURL = configMap[ASSIGNMENT_URL_KEY].toString(); - - if (!assignmentURL.isEmpty()) { - // check the json for a pool - const QString ASSIGNMENT_POOL_KEY = "pool"; - QString assignmentPool = configMap[ASSIGNMENT_POOL_KEY].toString(); - - // check for a number of instances, if not passed then default is 1 - const QString ASSIGNMENT_INSTANCES_KEY = "instances"; - int numInstances = configMap[ASSIGNMENT_INSTANCES_KEY].toInt(); - numInstances = (numInstances == 0 ? 1 : numInstances); - - qDebug() << "Adding a static scripted assignment from" << assignmentURL; - - for (int i = 0; i < numInstances; i++) { +void DomainServer::populateStaticScriptedAssignmentsFromSettings() { + const QString PERSISTENT_SCRIPTS_KEY_PATH = "scripts.persistent_scripts"; + const QVariant* persistentScriptsVariant = valueForKeyPath(_settingsManager.getSettingsMap(), PERSISTENT_SCRIPTS_KEY_PATH); + + if (persistentScriptsVariant) { + QVariantList persistentScriptsList = persistentScriptsVariant->toList(); + foreach(const QVariant& persistentScriptVariant, persistentScriptsList) { + QVariantMap persistentScript = persistentScriptVariant.toMap(); + + const QString PERSISTENT_SCRIPT_URL_KEY = "url"; + const QString PERSISTENT_SCRIPT_NUM_INSTANCES_KEY = "num_instances"; + const QString PERSISTENT_SCRIPT_POOL_KEY = "pool"; + + if (persistentScript.contains(PERSISTENT_SCRIPT_URL_KEY)) { + // check how many instances of this script to add + + int numInstances = persistentScript[PERSISTENT_SCRIPT_NUM_INSTANCES_KEY].toInt(); + QString scriptURL = persistentScript[PERSISTENT_SCRIPT_URL_KEY].toString(); + + QString scriptPool = persistentScript.value(PERSISTENT_SCRIPT_POOL_KEY).toString(); + + qDebug() << "Adding" << numInstances << "of persistent script at URL" << scriptURL << "- pool" << scriptPool; + + for (int i = 0; i < numInstances; ++i) { // add a scripted assignment to the queue for this instance Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType, - assignmentPool); - scriptAssignment->setPayload(assignmentURL.toUtf8()); - - // scripts passed on CL or via JSON are static - so they are added back to the queue if the node dies + scriptPool); + scriptAssignment->setPayload(scriptURL.toUtf8()); + + // add it to static hash so we know we have to keep giving it back out addStaticAssignmentToAssignmentHash(scriptAssignment); } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 76ab562f74..f910534eb1 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -100,9 +100,9 @@ private: void parseAssignmentConfigs(QSet& excludedTypes); void addStaticAssignmentToAssignmentHash(Assignment* newAssignment); - void createScriptedAssignmentsFromList(const QVariantList& configList); void createStaticAssignmentsForType(Assignment::Type type, const QVariantList& configList); void populateDefaultStaticAssignmentsExcludingTypes(const QSet& excludedTypes); + void populateStaticScriptedAssignmentsFromSettings(); SharedAssignmentPointer matchingQueuedAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType); SharedAssignmentPointer deployableAssignmentForRequest(const Assignment& requestAssignment); diff --git a/examples/developerMenuItems.js b/examples/developerMenuItems.js index 34bd3b3a75..3a274c7083 100644 --- a/examples/developerMenuItems.js +++ b/examples/developerMenuItems.js @@ -23,12 +23,8 @@ function setupMenus() { Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Bounds", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Children", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Do Precision Picking", isCheckable: true, isChecked: false }); - Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt to Reduce Material Switches", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt Render Entities as Scene", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Do Precision Picking", isCheckable: true, isChecked: false }); - Menu.addMenu("Developer > Entities > Culling"); - Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Out Of View Mesh Parts", isCheckable: true, isChecked: false }); - Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Too Small Mesh Parts", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false }); } } diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 622822e108..b1c258dc31 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -195,7 +195,7 @@ Grid = function(opts) { Overlays.editOverlay(gridOverlay, { position: { x: origin.y, y: origin.y, z: -origin.y }, visible: that.visible && that.enabled, - minorGridSpacing: minorGridSpacing, + minorGridWidth: minorGridSpacing, majorGridEvery: majorGridEvery, color: gridColor, alpha: gridAlpha, diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 38dd02c655..8c7b7b2211 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -107,7 +107,8 @@ endif() add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) # link required hifi libraries -link_hifi_libraries(shared octree voxels gpu fbx metavoxels networking entities avatars audio animation script-engine physics) +link_hifi_libraries(shared octree voxels gpu fbx metavoxels networking entities avatars audio animation script-engine physics + render-utils entities-renderer) # find any optional and required libraries find_package(ZLIB REQUIRED) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9f932c3bf1..77597e695f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -54,20 +54,27 @@ #include #include +#include #include +#include #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include +#include #include #include +#include #include #include @@ -87,10 +94,10 @@ #include "devices/TV3DManager.h" #include "devices/Visage.h" -#include "renderer/ProgramObject.h" #include "gpu/Batch.h" #include "gpu/GLBackend.h" + #include "scripting/AccountScriptingInterface.h" #include "scripting/AudioDeviceScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" @@ -106,7 +113,7 @@ #include "ui/InfoView.h" #include "ui/Snapshot.h" #include "ui/Stats.h" -#include "ui/TextRenderer.h" + using namespace std; @@ -135,19 +142,9 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt } } -QString& Application::resourcesPath() { -#ifdef Q_OS_MAC - static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; -#else - static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; -#endif - return staticResourcePath; -} - Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QApplication(argc, argv), _window(new MainWindow(desktop())), - _glWidget(new GLCanvas()), _toolWindow(NULL), _nodeThread(new QThread(this)), _datagramProcessor(), @@ -160,9 +157,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _voxelImporter(), _importSucceded(false), _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), - _entities(true), + _entities(true, this, this), _entityCollisionSystem(), - _entityClipboardRenderer(false), + _entityClipboardRenderer(false, this, this), _entityClipboard(), _wantToKillLocalVoxels(false), _viewFrustum(), @@ -195,8 +192,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _isVSyncOn(true), _aboutToQuit(false) { + GLCanvas::SharedPointer glCanvas = DependencyManager::get(); + Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us + // read the ApplicationInfo.ini file for Name/Version/Domain information - QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); + QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); // set the associated application properties applicationInfo.beginGroup("INFO"); @@ -214,7 +214,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _applicationStartupTime = startup_time; - QFontDatabase::addApplicationFont(Application::resourcesPath() + "styles/Inconsolata.otf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); _window->setWindowTitle("Interface"); qInstallMessageHandler(messageHandler); @@ -251,7 +251,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // put the audio processing on a separate thread QThread* audioThread = new QThread(this); - Audio* audioIO = DependencyManager::get