From e9e9607a3b4d07bf47faa0178166d4e0c4f64a20 Mon Sep 17 00:00:00 2001 From: kasenvr Date: Tue, 9 Jul 2019 19:17:03 -0400 Subject: [PATCH 01/20] modkit core changes initial commit whitespace corrections + warnings updated cmake plugin rework with focus on JS API integration example cleanup edit_filter scope separate-out edit_filter wantsScope stuff -plugin metadata split scriptengines out separately cleanup __url/__filename sets additional cleanup fix typo; consolidate ScriptInitializerMixin inits add more example API protoypes cleanup pass; fix entity_server / agent init fix whitespace remove technically unnessary plugin filtering +EDIT_FILTER_SCRIPT; cleanup reorder public/slot/private use std::count_if formatting better debug output; cleanup fix msvc compiler warning cleanup eradicate QtScript references from API Example updated header comments Updated KasenAPIExample --- assignment-client/src/Agent.cpp | 3 +- assignment-client/src/AssignmentClientApp.cpp | 2 + .../src/entities/EntityServer.cpp | 2 + .../src/scripts/EntityScriptServer.cpp | 4 +- interface/src/Application.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 4 +- libraries/entities/src/EntityEditFilters.cpp | 9 +- libraries/networking/src/Assignment.cpp | 2 +- .../networking/src/ThreadedAssignment.cpp | 3 + .../plugins/src/plugins/PluginManager.cpp | 7 +- libraries/plugins/src/plugins/PluginManager.h | 1 + libraries/script-engine/src/ScriptEngine.cpp | 6 + libraries/script-engine/src/ScriptEngine.h | 7 +- libraries/script-engine/src/ScriptEngines.cpp | 28 +--- libraries/script-engine/src/ScriptEngines.h | 15 +- .../src/shared/ScriptInitializerMixin.h | 40 +++-- plugins/CMakeLists.txt | 4 + plugins/KasenAPIExample/CMakeLists.txt | 7 + .../src/DeprecatedScriptPlugin.h | 58 ++++++++ .../KasenAPIExample/src/KasenAPIExample.cpp | 139 ++++++++++++++++++ plugins/KasenAPIExample/src/plugin.json | 21 +++ 21 files changed, 302 insertions(+), 62 deletions(-) create mode 100644 plugins/KasenAPIExample/CMakeLists.txt create mode 100644 plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h create mode 100644 plugins/KasenAPIExample/src/KasenAPIExample.cpp create mode 100644 plugins/KasenAPIExample/src/plugin.json diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 3937d5f799..68464fef91 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -84,7 +84,7 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::get()->setPacketSender(&_entityEditSender); DependencyManager::set(); - DependencyManager::set(); + DependencyManager::set()->instantiate(); DependencyManager::registerInheritance(); @@ -511,6 +511,7 @@ void Agent::executeScript() { DependencyManager::set(_entityViewer.getTree()); + DependencyManager::get()->runScriptInitializers(_scriptEngine); _scriptEngine->run(); Frame::clearFrameHandler(AUDIO_FRAME_TYPE); diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index a87200dc5b..2fa052e244 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "Assignment.h" #include "AssignmentClient.h" @@ -240,6 +241,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : QThread::currentThread()->setObjectName("main thread"); DependencyManager::registerInheritance(); + DependencyManager::set(); if (numForks || minForks || maxForks) { AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 06632dabb0..4bfe5c67c1 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ EntityServer::EntityServer(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set()->instantiate(); DependencyManager::registerInheritance(); DependencyManager::set(); diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index f1a6c97831..82b8eb3f20 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -64,7 +64,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); + DependencyManager::set()->instantiate(); DependencyManager::registerInheritance(); @@ -454,7 +454,7 @@ void EntityScriptServer::resetEntitiesScriptEngine() { _entityViewer.getTree()->update(); }); - + scriptEngines->runScriptInitializers(newEngine); newEngine->runInThread(); auto newEngineSP = qSharedPointerCast(newEngine); DependencyManager::get()->setEntitiesScriptEngine(newEngineSP); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9aa2bdbcdb..0b56b2a4d7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -814,6 +814,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { } // Tell the plugin manager about our statically linked plugins + DependencyManager::set(); DependencyManager::set(); auto pluginManager = PluginManager::getInstance(); pluginManager->setInputPluginProvider([] { return getInputPlugins(); }); @@ -863,7 +864,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { #endif DependencyManager::set(); DependencyManager::set(ScriptEngine::CLIENT_SCRIPT, defaultScriptsOverrideOption); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 5cb7b89de5..0947052399 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include @@ -146,7 +146,7 @@ int EntityTreeRenderer::_entitiesScriptEngineCount = 0; void EntityTreeRenderer::resetEntitiesScriptEngine() { _entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount)); - _scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine); + DependencyManager::get()->runScriptInitializers(_entitiesScriptEngine); _entitiesScriptEngine->runInThread(); auto entitiesScriptEngineProvider = qSharedPointerCast(_entitiesScriptEngine); auto entityScriptingInterface = DependencyManager::get(); diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index a763c0f146..a222ca8216 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -14,6 +14,7 @@ #include #include +#include QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { QList zones; @@ -258,7 +259,13 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { if (hasCorrectSyntax(program)) { // create a QScriptEngine for this script QScriptEngine* engine = new QScriptEngine(); - engine->evaluate(scriptContents); + engine->setObjectName("filter:" + entityID.toString()); + engine->setProperty("type", "edit_filter"); + engine->setProperty("fileName", urlString); + engine->setProperty("entityID", entityID); + engine->globalObject().setProperty("Script", engine->newQObject(engine)); + DependencyManager::get()->runScriptInitializers(engine); + engine->evaluate(scriptContents, urlString); if (!hadUncaughtExceptions(*engine, urlString)) { // put the engine in the engine map (so we don't leak them, etc...) FilterData filterData; diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 71a3cfb269..735f6dbc74 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -154,7 +154,7 @@ const char* Assignment::typeToString(Assignment::Type type) { QDebug operator<<(QDebug debug, const Assignment &assignment) { debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) << - ", Type: " << assignment.getType(); + ", Type: " << assignment.getTypeName() << " (" << assignment.getType() << ")"; if (!assignment.getPool().isEmpty()) { debug << ", Pool: " << assignment.getPool(); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index b8a8f65080..e680b22fdc 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -29,6 +29,9 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) : _domainServerTimer(this), _statsTimer(this) { + // use as a temporary targetName name until commonInit can be called later + LogHandler::getInstance().setTargetName(QString("<%1>").arg(getTypeName())); + static const int STATS_TIMEOUT_MS = 1000; _statsTimer.setInterval(STATS_TIMEOUT_MS); // 1s, Qt::CoarseTimer acceptable connect(&_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 0d0209e35f..420842b453 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -84,6 +84,11 @@ bool isDisabled(QJsonObject metaData) { return false; } +int PluginManager::instantiate() { + auto loaders = getLoadedPlugins(); + return std::count_if(loaders.begin(), loaders.end(), [](const auto& loader) { return (bool)loader->instance(); }); +} + auto PluginManager::getLoadedPlugins() const -> const LoaderList& { static std::once_flag once; static LoaderList loadedPlugins; @@ -139,7 +144,7 @@ bool isDisabled(QJsonObject metaData) { qCDebug(plugins) << " " << qPrintable(loader->errorString()); } } - } + } else qWarning() << "pluginPath does not exit..." << pluginDir; }); return loadedPlugins; } diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h index 1a578c7406..e0d35a690d 100644 --- a/libraries/plugins/src/plugins/PluginManager.h +++ b/libraries/plugins/src/plugins/PluginManager.h @@ -38,6 +38,7 @@ public: void saveSettings(); void setContainer(PluginContainer* container) { _container = container; } + int instantiate(); void shutdown(); // Application that have statically linked plugins can expose them to the plugin manager with these function diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 5e20f06a7f..4bf38070c4 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -190,6 +190,7 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const case Context::ENTITY_SERVER_SCRIPT: _type = Type::ENTITY_SERVER; break; + case Context::EDIT_FILTER_SCRIPT: case Context::AGENT_SCRIPT: _type = Type::AGENT; break; @@ -236,6 +237,11 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const } } +QString ScriptEngine::getTypeAsString() const { + auto value = QVariant::fromValue(_type).toString(); + return value.isEmpty() ? "unknown" : value.toLower(); +} + QString ScriptEngine::getContext() const { switch (_context) { case CLIENT_SCRIPT: diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 52ece63dc2..bca3e02a96 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -122,13 +122,16 @@ public: class ScriptEngine : public BaseScriptEngine, public EntitiesScriptEngineProvider { Q_OBJECT Q_PROPERTY(QString context READ getContext) + Q_PROPERTY(QString type READ getTypeAsString) + Q_PROPERTY(QString fileName MEMBER _fileNameString CONSTANT) public: enum Context { CLIENT_SCRIPT, ENTITY_CLIENT_SCRIPT, ENTITY_SERVER_SCRIPT, - AGENT_SCRIPT + AGENT_SCRIPT, + EDIT_FILTER_SCRIPT }; enum Type { @@ -138,6 +141,7 @@ public: AGENT, AVATAR }; + Q_ENUM(Type) static int processLevelMaxRetries; ScriptEngine(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine")); @@ -274,6 +278,7 @@ public: * */ Q_INVOKABLE QString getContext() const; + Q_INVOKABLE QString getTypeAsString() const; /**jsdoc * Checks whether the script is running as an Interface or avatar script. diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index f94fca3463..05eefc66df 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -136,24 +136,6 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) { QObject* scriptsModel(); -bool NativeScriptInitializers::registerNativeScriptInitializer(NativeScriptInitializer initializer) { - return registerScriptInitializer([initializer](ScriptEnginePointer engine) { - initializer(qobject_cast(engine.data())); - }); -} - -bool NativeScriptInitializers::registerScriptInitializer(ScriptInitializer initializer) { - if (auto scriptEngines = DependencyManager::get().data()) { - scriptEngines->registerScriptInitializer(initializer); - return true; - } - return false; -} - -void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) { - _scriptInitializers.push_back(initializer); -} - void ScriptEngines::addScriptEngine(ScriptEnginePointer engine) { if (!_isStopped) { QMutexLocker locker(&_allScriptsMutex); @@ -559,12 +541,10 @@ void ScriptEngines::quitWhenFinished() { } int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) { - int ii=0; - for (auto initializer : _scriptInitializers) { - ii++; - initializer(scriptEngine); - } - return ii; + auto nativeCount = DependencyManager::get()->runScriptInitializers(scriptEngine.data()); + return nativeCount + std::count_if(_scriptInitializers.begin(), _scriptInitializers.end(), + [scriptEngine](auto initializer){ initializer(scriptEngine); return true; } + ); } void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) { diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index de836a3e09..2cc4fe892e 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -40,13 +40,7 @@ class ScriptEngine; * @property {ScriptsModelFilter} scriptsModelFilter */ -class NativeScriptInitializers : public ScriptInitializerMixin { -public: - bool registerNativeScriptInitializer(NativeScriptInitializer initializer) override; - bool registerScriptInitializer(ScriptInitializer initializer) override; -}; - -class ScriptEngines : public QObject, public Dependency { +class ScriptEngines : public QObject, public Dependency, public ScriptInitializerMixin { Q_OBJECT Q_PROPERTY(ScriptsModel* scriptsModel READ scriptsModel CONSTANT) @@ -54,11 +48,9 @@ class ScriptEngines : public QObject, public Dependency { Q_PROPERTY(QString debugScriptUrl READ getDebugScriptUrl WRITE setDebugScriptUrl) public: - using ScriptInitializer = ScriptInitializerMixin::ScriptInitializer; - ScriptEngines(ScriptEngine::Context context, const QUrl& defaultScriptsOverride = QUrl()); - void registerScriptInitializer(ScriptInitializer initializer); - int runScriptInitializers(ScriptEnginePointer engine); + int runScriptInitializers(ScriptEnginePointer engine) override; + void loadScripts(); void saveScripts(); @@ -277,7 +269,6 @@ protected: QHash _scriptEnginesHash; QSet _allKnownScriptEngines; QMutex _allScriptsMutex; - std::list _scriptInitializers; ScriptsModel _scriptsModel; ScriptsModelFilter _scriptsModelFilter; std::atomic _isStopped { false }; diff --git a/libraries/shared/src/shared/ScriptInitializerMixin.h b/libraries/shared/src/shared/ScriptInitializerMixin.h index 50de553b0b..cefa33c2d3 100644 --- a/libraries/shared/src/shared/ScriptInitializerMixin.h +++ b/libraries/shared/src/shared/ScriptInitializerMixin.h @@ -9,30 +9,38 @@ #pragma once #include +#include #include #include "../DependencyManager.h" class QScriptEngine; class ScriptEngine; -class ScriptInitializerMixin : public QObject, public Dependency { - Q_OBJECT +template class ScriptInitializerMixin { +public: + using ScriptInitializer = std::function; + virtual void registerScriptInitializer(ScriptInitializer initializer) { + InitializerLock lock(_scriptInitializerMutex); + _scriptInitializers.push_back(initializer); + } + virtual int runScriptInitializers(T engine) { + InitializerLock lock(_scriptInitializerMutex); + return std::count_if(_scriptInitializers.begin(), _scriptInitializers.end(), + [engine](auto initializer){ initializer(engine); return true; } + ); + } + virtual ~ScriptInitializerMixin() {} +protected: + std::mutex _scriptInitializerMutex; + using InitializerLock = std::lock_guard; + std::list _scriptInitializers; +}; + +class ScriptInitializers : public ScriptInitializerMixin, public Dependency { public: // Lightweight `QScriptEngine*` initializer (only depends on built-in Qt components) // example registration: - // eg: [&](QScriptEngine* engine) -> bool { + // eg: [&](QScriptEngine* engine) { // engine->globalObject().setProperties("API", engine->newQObject(...instance...)) - // return true; - // } - using NativeScriptInitializer = std::function; - virtual bool registerNativeScriptInitializer(NativeScriptInitializer initializer) = 0; - - // Heavyweight `ScriptEngine*` initializer (tightly coupled to Interface and script-engine library internals) - // eg: [&](ScriptEnginePointer scriptEngine) -> bool { - // engine->registerGlobalObject("API", ...instance..); - // return true; - // } - using ScriptEnginePointer = QSharedPointer; - using ScriptInitializer = std::function; - virtual bool registerScriptInitializer(ScriptInitializer initializer) { return false; }; + // }; }; diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 4a0f52e272..1150e27cac 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -43,3 +43,7 @@ set(DIR "pcmCodec") add_subdirectory(${DIR}) set(DIR "hifiCodec") add_subdirectory(${DIR}) + +# example plugins +set(DIR "KasenAPIExample") +add_subdirectory(${DIR}) diff --git a/plugins/KasenAPIExample/CMakeLists.txt b/plugins/KasenAPIExample/CMakeLists.txt new file mode 100644 index 0000000000..51406fbd45 --- /dev/null +++ b/plugins/KasenAPIExample/CMakeLists.txt @@ -0,0 +1,7 @@ +set(TARGET_NAME KasenAPIExample) +setup_hifi_client_server_plugin() +link_hifi_libraries(shared plugins avatars networking graphics gpu) + +if (BUILD_SERVER) + install_beside_console() +endif() diff --git a/plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h b/plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h new file mode 100644 index 0000000000..dc2b660066 --- /dev/null +++ b/plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h @@ -0,0 +1,58 @@ +// +// DeprecatedScriptPlugin.h +// plugins/KasenAPIExample/src +// +// Created by Kasen IO on 2019.07.14 | realities.dev | kasenvr@gmail.com +// Copyright 2019 Kasen IO +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Supporting file containing all QtScript specific integration. + +#ifndef DEPRECATED_SCRIPT_PLUGIN_H +#define DEPRECATED_SCRIPT_PLUGIN_H + +#if DEV_BUILD +#pragma message("QtScript is deprecated see: doc.qt.io/qt-5/topics-scripting.html") +#endif +#include + +#include +#include +#include + +namespace deprecated { + +extern const QLoggingCategory& logger; + +inline void setGlobalInstance(QScriptEngine* engine, const QString& name, QObject* object) { + auto value = engine->newQObject(object, QScriptEngine::QtOwnership); + engine->globalObject().setProperty(name, value); + if (1 || getenv("DEBUG")) { + qCDebug(logger) << "(via ScriptInitializers)...setGlobalInstance" << name << engine->property("fileName"); + } +} + +class ScriptPlugin : public QObject { + Q_OBJECT + QString _version; + Q_PROPERTY(QString version MEMBER _version CONSTANT) +protected: + inline ScriptPlugin(const QString& name, const QString& version) : _version(version) { + setObjectName(name); + if (!DependencyManager::get()) { + qCWarning(logger) << "COULD NOT INITIALIZE (ScriptInitializers unavailable)" << qApp << this; + return; + } + qCWarning(logger) << "registering w/ScriptInitializerMixin..." << DependencyManager::get().data(); + DependencyManager::get()->registerScriptInitializer( + [this](QScriptEngine* engine) { setGlobalInstance(engine, objectName(), this); }); + } +public slots: + inline QString toString() const { return QString("[%1 version=%2]").arg(objectName()).arg(_version); } +}; + +} // namespace deprecated + +#endif \ No newline at end of file diff --git a/plugins/KasenAPIExample/src/KasenAPIExample.cpp b/plugins/KasenAPIExample/src/KasenAPIExample.cpp new file mode 100644 index 0000000000..f6823ebded --- /dev/null +++ b/plugins/KasenAPIExample/src/KasenAPIExample.cpp @@ -0,0 +1,139 @@ +// +// KasenAPIExample.cpp +// plugins/KasenAPIExample/src +// +// Created by Kasen IO on 2019.07.14 | realities.dev | kasenvr@gmail.com +// Copyright 2019 Kasen IO +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Example of prototyping new JS APIs by leveraging the existing plugin system. + +#include "DeprecatedScriptPlugin.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace custom_api_example { + +QLoggingCategory logger{ "custom_api_example" }; + +class KasenAPIExample : public deprecated::ScriptPlugin { + Q_OBJECT + Q_PLUGIN_METADATA(IID "KasenAPIExample" FILE "plugin.json") +public: + KasenAPIExample() : deprecated::ScriptPlugin("KasenAPIExample", "0.0.0") { + qCInfo(logger) << "plugin loaded" << qApp << toString() << QThread::currentThread(); + } + +public slots: + /**jsdoc + * Returns current microseconds (usecs) since Epoch. note: 1000usecs == 1ms + * @example Measure current setTimeout accuracy. + * var expected = 1000; + * var start = KasenAPIExample.now(); + * Script.setTimeout(function () { + * var elapsed = (KasenAPIExample.now() - start)/1000; + * print("expected (ms):", expected, "actual (ms):", elapsed); + * }, expected); + */ + QVariant now() const { + return usecTimestampNow(); + } + + /**jsdoc + * Returns the available blendshape names for an avatar. + * @example Get blendshape names + * print(JSON.stringify(KasenAPIExample.getBlendshapeNames(MyAvatar.sessionUUID))); + */ + QStringList getBlendshapeNames(const QUuid& avatarID) const { + QVector out; + if (auto head = getAvatarHead(avatarID)) { + for (const auto& kv : head->getBlendshapeMap().toStdMap()) { + if (kv.second >= out.size()) out.resize(kv.second+1); + out[kv.second] = kv.first; + } + } + return out.toList(); + } + + /**jsdoc + * Returns a key-value object with active (non-zero) blendshapes. + * eg: { JawOpen: 1.0, ... } + * @example Get active blendshape map + * print(JSON.stringify(KasenAPIExample.getActiveBlendshapes(MyAvatar.sessionUUID))); + */ + QVariant getActiveBlendshapes(const QUuid& avatarID) const { + if (auto head = getAvatarHead(avatarID)) { + return head->toJson()["blendShapes"].toVariant(); + } + return {}; + } + + QVariant getBlendshapeMapping(const QUuid& avatarID) const { + QVariantMap out; + if (auto head = getAvatarHead(avatarID)) { + for (const auto& kv : head->getBlendshapeMap().toStdMap()) { + out[kv.first] = kv.second; + } + } + return out; + } + + QVariant getBlendshapes(const QUuid& avatarID) const { + QVariantMap result; + if (auto head = getAvatarHead(avatarID)) { + QStringList names = getBlendshapeNames(avatarID); + auto states = head->getBlendshapeStates(); + result = { + { "base", zipNonZeroValues(names, states.base) }, + { "summed", zipNonZeroValues(names, states.summed) }, + { "transient", zipNonZeroValues(names, states.transient) }, + }; + } + return result; + } + +private: + static QVariantMap zipNonZeroValues(const QStringList& keys, const QVector& values) { + QVariantMap out; + for (int i=1; i < values.size(); i++) { + if (fabs(values[i]) > 1.0e-6f) { + out[keys.value(i)] = values[i]; + } + } + return out; + } + struct _HeadHelper : public HeadData { + QMap getBlendshapeMap() const { + return _blendshapeLookupMap; + } + struct States { QVector base, summed, transient; }; + States getBlendshapeStates() const { + return { + _blendshapeCoefficients, + _summedBlendshapeCoefficients, + _transientBlendshapeCoefficients + }; + } + }; + static const _HeadHelper* getAvatarHead(const QUuid& avatarID) { + auto avatars = DependencyManager::get(); + auto avatar = avatars ? avatars->getAvatarBySessionID(avatarID) : nullptr; + auto head = avatar ? avatar->getHeadData() : nullptr; + return reinterpret_cast(head); + } +}; + +} + +const QLoggingCategory& deprecated::logger{ custom_api_example::logger }; + +#include "KasenAPIExample.moc" diff --git a/plugins/KasenAPIExample/src/plugin.json b/plugins/KasenAPIExample/src/plugin.json new file mode 100644 index 0000000000..2d113c700f --- /dev/null +++ b/plugins/KasenAPIExample/src/plugin.json @@ -0,0 +1,21 @@ +{ + "name":"Kasen JS API Example", + "version": 1, + "package": { + "author": "Revofire", + "homepage": "www.realities.dev", + "version": "0.0.0", + "engines": { + "hifi-interface": ">= 0.83.0", + "hifi-assignment-client": ">= 0.83.0" + }, + "config": { + "client": true, + "entity_client": true, + "entity_server": true, + "edit_filter": true, + "agent": true, + "avatar": true + } + } +} From c5b2514e0eb13172953aa90a9cf279b199dcac2b Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 23 Jul 2019 12:13:18 -0400 Subject: [PATCH 02/20] fix linux build warning; remove unnecessary code --- libraries/script-engine/src/ScriptEngine.cpp | 1 - libraries/script-engine/src/ScriptEngine.h | 3 +-- libraries/script-engine/src/ScriptEngines.cpp | 4 +--- plugins/KasenAPIExample/CMakeLists.txt | 4 ---- plugins/KasenAPIExample/src/KasenAPIExample.cpp | 2 +- 5 files changed, 3 insertions(+), 11 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 4bf38070c4..4fcd39d819 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -190,7 +190,6 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const case Context::ENTITY_SERVER_SCRIPT: _type = Type::ENTITY_SERVER; break; - case Context::EDIT_FILTER_SCRIPT: case Context::AGENT_SCRIPT: _type = Type::AGENT; break; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index bca3e02a96..b86d8f6315 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -130,8 +130,7 @@ public: CLIENT_SCRIPT, ENTITY_CLIENT_SCRIPT, ENTITY_SERVER_SCRIPT, - AGENT_SCRIPT, - EDIT_FILTER_SCRIPT + AGENT_SCRIPT }; enum Type { diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 05eefc66df..17f79574b9 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -542,9 +542,7 @@ void ScriptEngines::quitWhenFinished() { int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) { auto nativeCount = DependencyManager::get()->runScriptInitializers(scriptEngine.data()); - return nativeCount + std::count_if(_scriptInitializers.begin(), _scriptInitializers.end(), - [scriptEngine](auto initializer){ initializer(scriptEngine); return true; } - ); + return nativeCount + ScriptInitializerMixin::runScriptInitializers(scriptEngine); } void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) { diff --git a/plugins/KasenAPIExample/CMakeLists.txt b/plugins/KasenAPIExample/CMakeLists.txt index 51406fbd45..14e2dc0b3d 100644 --- a/plugins/KasenAPIExample/CMakeLists.txt +++ b/plugins/KasenAPIExample/CMakeLists.txt @@ -1,7 +1,3 @@ set(TARGET_NAME KasenAPIExample) setup_hifi_client_server_plugin() link_hifi_libraries(shared plugins avatars networking graphics gpu) - -if (BUILD_SERVER) - install_beside_console() -endif() diff --git a/plugins/KasenAPIExample/src/KasenAPIExample.cpp b/plugins/KasenAPIExample/src/KasenAPIExample.cpp index f6823ebded..f781c0be28 100644 --- a/plugins/KasenAPIExample/src/KasenAPIExample.cpp +++ b/plugins/KasenAPIExample/src/KasenAPIExample.cpp @@ -105,7 +105,7 @@ private: static QVariantMap zipNonZeroValues(const QStringList& keys, const QVector& values) { QVariantMap out; for (int i=1; i < values.size(); i++) { - if (fabs(values[i]) > 1.0e-6f) { + if (fabs(values[i]) > 1.0e-6) { out[keys.value(i)] = values[i]; } } From 6ae75ecafed3b06013b49fd30edd97ee2e040969 Mon Sep 17 00:00:00 2001 From: humbletim Date: Thu, 25 Jul 2019 21:53:17 -0400 Subject: [PATCH 03/20] segregated scripting/ plugins (re: permissions checkbox) --- cmake/macros/SetupHifiClientServerPlugin.cmake | 8 +++++++- libraries/plugins/src/plugins/PluginManager.cpp | 14 +++++++++++++- libraries/plugins/src/plugins/PluginManager.h | 4 ++++ plugins/KasenAPIExample/CMakeLists.txt | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/cmake/macros/SetupHifiClientServerPlugin.cmake b/cmake/macros/SetupHifiClientServerPlugin.cmake index bc66484c30..1ce0b0ca6e 100644 --- a/cmake/macros/SetupHifiClientServerPlugin.cmake +++ b/cmake/macros/SetupHifiClientServerPlugin.cmake @@ -7,7 +7,8 @@ # macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN) set(${TARGET_NAME}_SHARED 1) - setup_hifi_library(${ARGV}) + set(PLUGIN_SUBFOLDER ${ARGN}) + setup_hifi_library() if (BUILD_CLIENT) add_dependencies(interface ${TARGET_NAME}) @@ -27,6 +28,11 @@ macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN) set(SERVER_PLUGIN_PATH "plugins") endif() + if (PLUGIN_SUBFOLDER) + set(CLIENT_PLUGIN_PATH "${CLIENT_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}") + set(SERVER_PLUGIN_PATH "${SERVER_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}") + endif() + if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles") set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${CLIENT_PLUGIN_PATH}/") set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/${SERVER_PLUGIN_PATH}/") diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 420842b453..8f1184904e 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -110,6 +110,16 @@ int PluginManager::instantiate() { pluginDir.setNameFilters(QStringList() << "libplugins_lib*.so"); #endif auto candidates = pluginDir.entryList(); + + if (_enableScriptingPlugins.get()) { + QDir scriptingPluginDir{ pluginDir }; + scriptingPluginDir.cd("scripting"); + qCDebug(plugins) << "Loading scripting plugins from " << scriptingPluginDir.path(); + for (auto plugin : scriptingPluginDir.entryList()) { + candidates << "scripting/" + plugin; + } + } + for (auto plugin : candidates) { qCDebug(plugins) << "Attempting plugin" << qPrintable(plugin); QSharedPointer loader(new QPluginLoader(pluginPath + plugin)); @@ -144,7 +154,9 @@ int PluginManager::instantiate() { qCDebug(plugins) << " " << qPrintable(loader->errorString()); } } - } else qWarning() << "pluginPath does not exit..." << pluginDir; + } else { + qWarning() << "pluginPath does not exit..." << pluginDir; + } }); return loadedPlugins; } diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h index e0d35a690d..eb377a2c8e 100644 --- a/libraries/plugins/src/plugins/PluginManager.h +++ b/libraries/plugins/src/plugins/PluginManager.h @@ -10,6 +10,7 @@ #include #include +#include #include "Forward.h" @@ -70,6 +71,9 @@ private: using LoaderList = QList; const LoaderList& getLoadedPlugins() const; + Setting::Handle _enableScriptingPlugins { + "private/enableScriptingPlugins", (bool)qgetenv("enableScriptingPlugins").toInt() + }; }; // TODO: we should define this value in CMake, and then use CMake diff --git a/plugins/KasenAPIExample/CMakeLists.txt b/plugins/KasenAPIExample/CMakeLists.txt index 14e2dc0b3d..96ac84e10d 100644 --- a/plugins/KasenAPIExample/CMakeLists.txt +++ b/plugins/KasenAPIExample/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME KasenAPIExample) -setup_hifi_client_server_plugin() +setup_hifi_client_server_plugin(scripting) link_hifi_libraries(shared plugins avatars networking graphics gpu) From d334a2e5e2b1b808b5622a14d46eabd0dba278c4 Mon Sep 17 00:00:00 2001 From: humbletim Date: Thu, 25 Jul 2019 21:50:58 -0400 Subject: [PATCH 04/20] QML-only write access for 'private/' Settings keys --- interface/src/Application.cpp | 4 ++-- .../src/scripting/SettingsScriptingInterface.cpp | 9 +++++++++ interface/src/scripting/SettingsScriptingInterface.h | 11 ++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0b56b2a4d7..a20d6dd440 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3393,7 +3393,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("Window", DependencyManager::get().data()); surfaceContext->setContextProperty("Desktop", DependencyManager::get().data()); surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); - surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); + surfaceContext->setContextProperty("Settings", new QMLSettingsScriptingInterface(surfaceContext)); surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get().data()); surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get().data()); @@ -3509,7 +3509,7 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona surfaceContext->setContextProperty("offscreenFlags", flags); surfaceContext->setContextProperty("AddressManager", DependencyManager::get().data()); - surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); + surfaceContext->setContextProperty("Settings", new QMLSettingsScriptingInterface(surfaceContext)); surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); surfaceContext->setContextProperty("Performance", new PerformanceScriptingInterface()); diff --git a/interface/src/scripting/SettingsScriptingInterface.cpp b/interface/src/scripting/SettingsScriptingInterface.cpp index afafe1a350..a118f9cf4f 100644 --- a/interface/src/scripting/SettingsScriptingInterface.cpp +++ b/interface/src/scripting/SettingsScriptingInterface.cpp @@ -11,6 +11,7 @@ #include "SettingsScriptingInterface.h" +#include #include SettingsScriptingInterface* SettingsScriptingInterface::getInstance() { @@ -35,6 +36,14 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVar } void SettingsScriptingInterface::setValue(const QString& setting, const QVariant& value) { + if (setting.startsWith("private/")) { + if (_restrictPrivateValues) { + qWarning() << "SettingsScriptingInterface::setValue -- restricted write: " << setting << value; + return; + } else { + qInfo() << "SettingsScriptingInterface::setValue -- allowing restricted write: " << setting << value; + } + } // Make a deep-copy of the string. // Dangling pointers can occur with QStrings that are implicitly shared from a QScriptEngine. QString deepCopy = QString::fromUtf16(setting.utf16()); diff --git a/interface/src/scripting/SettingsScriptingInterface.h b/interface/src/scripting/SettingsScriptingInterface.h index 25a8b627cb..633405dcc6 100644 --- a/interface/src/scripting/SettingsScriptingInterface.h +++ b/interface/src/scripting/SettingsScriptingInterface.h @@ -27,7 +27,6 @@ class SettingsScriptingInterface : public QObject { Q_OBJECT - SettingsScriptingInterface() { }; public: static SettingsScriptingInterface* getInstance(); @@ -64,6 +63,16 @@ public slots: * print("Value: " + (typeof value) + " " + JSON.stringify(value)); // object {"x":0,"y":10,"z":0} */ void setValue(const QString& setting, const QVariant& value); + +protected: + SettingsScriptingInterface(QObject* parent = nullptr) : QObject(parent) { }; + bool _restrictPrivateValues { true }; +}; + +class QMLSettingsScriptingInterface : public SettingsScriptingInterface { + Q_OBJECT +public: + QMLSettingsScriptingInterface(QObject* parent) : SettingsScriptingInterface(parent) { _restrictPrivateValues = false; } }; #endif // hifi_SettingsScriptingInterface_h From 52d2938be3eb6acd0df593ddd0dfa176fb79d48c Mon Sep 17 00:00:00 2001 From: humbletim Date: Thu, 25 Jul 2019 21:47:56 -0400 Subject: [PATCH 05/20] DeprecatedScriptPlugin => ExampleScriptPlugin --- ...recatedScriptPlugin.h => ExampleScriptPlugin.h} | 14 ++++++-------- plugins/KasenAPIExample/src/KasenAPIExample.cpp | 8 ++++---- plugins/KasenAPIExample/src/plugin.json | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) rename plugins/KasenAPIExample/src/{DeprecatedScriptPlugin.h => ExampleScriptPlugin.h} (85%) diff --git a/plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h b/plugins/KasenAPIExample/src/ExampleScriptPlugin.h similarity index 85% rename from plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h rename to plugins/KasenAPIExample/src/ExampleScriptPlugin.h index dc2b660066..a6af105e0e 100644 --- a/plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h +++ b/plugins/KasenAPIExample/src/ExampleScriptPlugin.h @@ -1,5 +1,5 @@ // -// DeprecatedScriptPlugin.h +// ExampleScriptPlugin.h // plugins/KasenAPIExample/src // // Created by Kasen IO on 2019.07.14 | realities.dev | kasenvr@gmail.com @@ -10,8 +10,8 @@ // // Supporting file containing all QtScript specific integration. -#ifndef DEPRECATED_SCRIPT_PLUGIN_H -#define DEPRECATED_SCRIPT_PLUGIN_H +#ifndef EXAMPLE_SCRIPT_PLUGIN_H +#define EXAMPLE_SCRIPT_PLUGIN_H #if DEV_BUILD #pragma message("QtScript is deprecated see: doc.qt.io/qt-5/topics-scripting.html") @@ -22,16 +22,14 @@ #include #include -namespace deprecated { +namespace example { extern const QLoggingCategory& logger; inline void setGlobalInstance(QScriptEngine* engine, const QString& name, QObject* object) { auto value = engine->newQObject(object, QScriptEngine::QtOwnership); engine->globalObject().setProperty(name, value); - if (1 || getenv("DEBUG")) { - qCDebug(logger) << "(via ScriptInitializers)...setGlobalInstance" << name << engine->property("fileName"); - } + qCDebug(logger) << "setGlobalInstance" << name << engine->property("fileName"); } class ScriptPlugin : public QObject { @@ -53,6 +51,6 @@ public slots: inline QString toString() const { return QString("[%1 version=%2]").arg(objectName()).arg(_version); } }; -} // namespace deprecated +} // namespace example #endif \ No newline at end of file diff --git a/plugins/KasenAPIExample/src/KasenAPIExample.cpp b/plugins/KasenAPIExample/src/KasenAPIExample.cpp index f781c0be28..d566d11376 100644 --- a/plugins/KasenAPIExample/src/KasenAPIExample.cpp +++ b/plugins/KasenAPIExample/src/KasenAPIExample.cpp @@ -10,7 +10,7 @@ // // Example of prototyping new JS APIs by leveraging the existing plugin system. -#include "DeprecatedScriptPlugin.h" +#include "ExampleScriptPlugin.h" #include #include @@ -25,11 +25,11 @@ namespace custom_api_example { QLoggingCategory logger{ "custom_api_example" }; -class KasenAPIExample : public deprecated::ScriptPlugin { +class KasenAPIExample : public example::ScriptPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "KasenAPIExample" FILE "plugin.json") public: - KasenAPIExample() : deprecated::ScriptPlugin("KasenAPIExample", "0.0.0") { + KasenAPIExample() : example::ScriptPlugin("KasenAPIExample", "0.0.1") { qCInfo(logger) << "plugin loaded" << qApp << toString() << QThread::currentThread(); } @@ -134,6 +134,6 @@ private: } -const QLoggingCategory& deprecated::logger{ custom_api_example::logger }; +const QLoggingCategory& example::logger{ custom_api_example::logger }; #include "KasenAPIExample.moc" diff --git a/plugins/KasenAPIExample/src/plugin.json b/plugins/KasenAPIExample/src/plugin.json index 2d113c700f..3e6931deec 100644 --- a/plugins/KasenAPIExample/src/plugin.json +++ b/plugins/KasenAPIExample/src/plugin.json @@ -4,7 +4,7 @@ "package": { "author": "Revofire", "homepage": "www.realities.dev", - "version": "0.0.0", + "version": "0.0.1", "engines": { "hifi-interface": ">= 0.83.0", "hifi-assignment-client": ">= 0.83.0" From bac59b52aa799d15ae5516df9d2fa9f717643929 Mon Sep 17 00:00:00 2001 From: Kalila R Date: Thu, 25 Jul 2019 21:06:20 -0400 Subject: [PATCH 06/20] Added checkbox for script plugins to security.qml --- .../qml/hifi/dialogs/security/Security.qml | 89 ++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/dialogs/security/Security.qml b/interface/resources/qml/hifi/dialogs/security/Security.qml index a7a0d461a2..b1f62633e7 100644 --- a/interface/resources/qml/hifi/dialogs/security/Security.qml +++ b/interface/resources/qml/hifi/dialogs/security/Security.qml @@ -240,9 +240,96 @@ Rectangle { } } + // -- Plugin Permissions -- + Item { + id: kpiContainer; + anchors.top: accountContainer.bottom; + anchors.left: parent.left; + anchors.right: parent.right; + height: childrenRect.height; + + Rectangle { + id: kpiHeaderContainer; + anchors.top: parent.top; + anchors.left: parent.left; + anchors.right: parent.right; + height: 55; + color: hifi.colors.baseGrayHighlight; + + HifiStylesUit.RalewaySemiBold { + text: "Plugin Permissions"; + anchors.fill: parent; + anchors.leftMargin: 20; + color: hifi.colors.white; + size: 18; + } + } + + Item { + id: kpiScriptContainer; + anchors.top: kpiHeaderContainer.bottom; + anchors.left: parent.left; + anchors.right: parent.right; + height: 80; + + HifiControlsUit.CheckBox { + id: kpiScriptCheckbox; + readonly property string kpiSettingsKey: "private/enableScriptingPlugins" + checked: Settings.getValue(kpiSettingsKey, false); + text: "Enable custom script plugins (requires restart)" + // Anchors + anchors.verticalCenter: parent.verticalCenter; + anchors.left: parent.left; + anchors.leftMargin: 20; + boxSize: 24; + labelFontSize: 18; + colorScheme: hifi.colorSchemes.dark + color: hifi.colors.white; + width: 300; + onCheckedChanged: Settings.setValue(kpiSettingsKey, checked); + } + + HifiStylesUit.RalewaySemiBold { + id: kpiScriptHelp; + text: '[?]'; + // Anchors + anchors.verticalCenter: parent.verticalCenter; + anchors.left: kpiScriptCheckbox.right; + width: 30; + height: 30; + // Text size + size: 18; + // Style + color: hifi.colors.blueHighlight; + + MouseArea { + anchors.fill: parent; + hoverEnabled: true; + onEntered: { + parent.color = hifi.colors.blueAccent; + } + onExited: { + parent.color = hifi.colors.blueHighlight; + } + onClicked: { + lightboxPopup.titleText = "Script Plugin Infrastructure by Kasen"; + lightboxPopup.bodyText = "Toggles the activation of scripting plugins in the 'plugins/scripting' folder. \n\n" + + "Created by https://kasen.io/"; + lightboxPopup.button1text = "OK"; + lightboxPopup.button1method = function() { + lightboxPopup.visible = false; + } + lightboxPopup.visible = true; + } + } + } + } + } + + Item { id: walletContainer; - anchors.top: accountContainer.bottom; + anchors.top: kpiContainer.bottom; anchors.left: parent.left; anchors.right: parent.right; height: childrenRect.height; From 8b6cce5889fd5cff08476f0ea6172b46c5ed7ca6 Mon Sep 17 00:00:00 2001 From: Kalila R Date: Tue, 30 Jul 2019 17:26:49 -0400 Subject: [PATCH 07/20] Moved getTypeAsString function from public to protected --- libraries/script-engine/src/ScriptEngine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index b86d8f6315..de60d89328 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -277,7 +277,6 @@ public: * */ Q_INVOKABLE QString getContext() const; - Q_INVOKABLE QString getTypeAsString() const; /**jsdoc * Checks whether the script is running as an Interface or avatar script. @@ -635,6 +634,7 @@ public: void setType(Type type) { _type = type; }; Type getType() { return _type; }; + QString getTypeAsString() const; bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget bool isRunning() const { return _isRunning; } // used by ScriptWidget From bad32e9916b3c54a0bd7ad484ccebea2b9358530 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 30 Jul 2019 17:33:48 -0400 Subject: [PATCH 08/20] remove unnecessary include --- interface/src/scripting/SettingsScriptingInterface.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/scripting/SettingsScriptingInterface.cpp b/interface/src/scripting/SettingsScriptingInterface.cpp index a118f9cf4f..ac1b389f85 100644 --- a/interface/src/scripting/SettingsScriptingInterface.cpp +++ b/interface/src/scripting/SettingsScriptingInterface.cpp @@ -11,7 +11,6 @@ #include "SettingsScriptingInterface.h" -#include #include SettingsScriptingInterface* SettingsScriptingInterface::getInstance() { From a49fe4844b8d6f67a17f0f1ce202dc7684c138ce Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 10 Sep 2019 12:30:20 -0700 Subject: [PATCH 09/20] BUGZ-1167: remove unwanted binaries from bad client-only installers --- cmake/templates/NSIS.template.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index cc7a6929a2..0db2592143 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1156,7 +1156,12 @@ FunctionEnd Section "-Core installation" - ;The following delete blocks are temporary and can be removed once users who had the initial installer have updated + ; 2016-02-25 - The following delete blocks are temporary and can be removed once users who had the initial installer have updated + ; 2019-09-10 - (3 and a half years later) Sure they are buddy. Sure they are. + + ;Delete any server executables that might have been installed by bad versions of the client-only installer + Delete "$INSTDIR\assignment-client.exe" + Delete "$INSTDIR\domain-server.exe" ;Delete any server-console files installed before it was placed in sub-folder Delete "$INSTDIR\server-console.exe" From 967e7db0bb64233a6162d1e1dbae0d2489cc762c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 10 Sep 2019 16:29:45 -0700 Subject: [PATCH 10/20] Don't break sandbox builds --- cmake/templates/NSIS.template.in | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 0db2592143..f06985d8be 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1159,9 +1159,11 @@ Section "-Core installation" ; 2016-02-25 - The following delete blocks are temporary and can be removed once users who had the initial installer have updated ; 2019-09-10 - (3 and a half years later) Sure they are buddy. Sure they are. - ;Delete any server executables that might have been installed by bad versions of the client-only installer - Delete "$INSTDIR\assignment-client.exe" - Delete "$INSTDIR\domain-server.exe" + ;Delete any server executables that might have been installed by bad versions of the client-only installer, but ONLY if we are a client-only installer + ${If} "@INSTALLER_TYPE@" == "client_only" + Delete "$INSTDIR\assignment-client.exe" + Delete "$INSTDIR\domain-server.exe" + ${EndIf} ;Delete any server-console files installed before it was placed in sub-folder Delete "$INSTDIR\server-console.exe" From 9be475bff83da88a5b40a4e55357a781b443b6e7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 10 Sep 2019 18:43:34 -0700 Subject: [PATCH 11/20] Trying to fix client-only build --- cmake/templates/NSIS.template.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index f06985d8be..e93c454e7e 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1159,8 +1159,11 @@ Section "-Core installation" ; 2016-02-25 - The following delete blocks are temporary and can be removed once users who had the initial installer have updated ; 2019-09-10 - (3 and a half years later) Sure they are buddy. Sure they are. + MessageBox MB_OK|MB_ICONEXCLAMATION "installer type is @INSTALLER_TYPE@" + ;Delete any server executables that might have been installed by bad versions of the client-only installer, but ONLY if we are a client-only installer ${If} "@INSTALLER_TYPE@" == "client_only" + MessageBox MB_OK|MB_ICONEXCLAMATION "trying to delete server binaries" Delete "$INSTDIR\assignment-client.exe" Delete "$INSTDIR\domain-server.exe" ${EndIf} From 790ac6a483bed5904ad2aeb107adf53512b4c3b2 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 10 Sep 2019 20:40:59 -0700 Subject: [PATCH 12/20] Removing debugging popups --- cmake/templates/NSIS.template.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e93c454e7e..9af99f927d 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1159,11 +1159,11 @@ Section "-Core installation" ; 2016-02-25 - The following delete blocks are temporary and can be removed once users who had the initial installer have updated ; 2019-09-10 - (3 and a half years later) Sure they are buddy. Sure they are. - MessageBox MB_OK|MB_ICONEXCLAMATION "installer type is @INSTALLER_TYPE@" + ; MessageBox MB_OK|MB_ICONEXCLAMATION "installer type is @INSTALLER_TYPE@" ;Delete any server executables that might have been installed by bad versions of the client-only installer, but ONLY if we are a client-only installer ${If} "@INSTALLER_TYPE@" == "client_only" - MessageBox MB_OK|MB_ICONEXCLAMATION "trying to delete server binaries" + ; MessageBox MB_OK|MB_ICONEXCLAMATION "trying to delete server binaries" Delete "$INSTDIR\assignment-client.exe" Delete "$INSTDIR\domain-server.exe" ${EndIf} From e9eb07d3886606586c6bc0a3a528706a1635b6e9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 11 Sep 2019 10:20:59 -0700 Subject: [PATCH 13/20] BUGZ-1339: Disable the Emote Indicator animation to prevent it from being 'jittery' --- .../simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/simplifiedUI/simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml b/scripts/simplifiedUI/simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml index 787ccadd62..bbd1d4d735 100644 --- a/scripts/simplifiedUI/simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml +++ b/scripts/simplifiedUI/simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml @@ -45,7 +45,8 @@ Rectangle { } Behavior on requestedWidth { - enabled: true + enabled: false // Set this to `true` once we have a different windowing system that better supports on-screen widgets + // like the Emote Indicator. SmoothedAnimation { duration: 220 } } From 5ec8b0d589e3a383ca7d83c4f5819091643c043c Mon Sep 17 00:00:00 2001 From: milad Date: Wed, 11 Sep 2019 11:39:19 -0700 Subject: [PATCH 14/20] added environment variable check for crash menu --- interface/src/Menu.cpp | 66 +++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8c6292681b..7c260e16b9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -725,45 +725,51 @@ Menu::Menu() { DependencyManager::get().data(), SLOT(setForceCoarsePicking(bool))); // Developer > Crash >>> - MenuWrapper* crashMenu = developerMenu->addMenu("Crash"); + bool result = false; + const QString HIFI_SHOW_SOURCE_DEVELOPER_CRASH_MENU("HIFI_SHOW_SOURCE_DEVELOPER_CRASH_MENU"); + result = QProcessEnvironment::systemEnvironment().contains(HIFI_SHOW_SOURCE_DEVELOPER_CRASH_MENU); + if (result) { + MenuWrapper* crashMenu = developerMenu->addMenu("Crash"); - // Developer > Crash > Display Crash Options - addCheckableActionToQMenuAndActionHash(crashMenu, MenuOption::DisplayCrashOptions, 0, true); + // Developer > Crash > Display Crash Options + addCheckableActionToQMenuAndActionHash(crashMenu, MenuOption::DisplayCrashOptions, 0, true); - addActionToQMenuAndActionHash(crashMenu, MenuOption::DeadlockInterface, 0, qApp, SLOT(deadlockApplication())); - addActionToQMenuAndActionHash(crashMenu, MenuOption::UnresponsiveInterface, 0, qApp, SLOT(unresponsiveApplication())); + addActionToQMenuAndActionHash(crashMenu, MenuOption::DeadlockInterface, 0, qApp, SLOT(deadlockApplication())); + addActionToQMenuAndActionHash(crashMenu, MenuOption::UnresponsiveInterface, 0, qApp, SLOT(unresponsiveApplication())); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunction); - connect(action, &QAction::triggered, qApp, []() { crash::pureVirtualCall(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunctionThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::pureVirtualCall).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunction); + connect(action, &QAction::triggered, qApp, []() { crash::pureVirtualCall(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunctionThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::pureVirtualCall).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFree); - connect(action, &QAction::triggered, qApp, []() { crash::doubleFree(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFreeThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doubleFree).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFree); + connect(action, &QAction::triggered, qApp, []() { crash::doubleFree(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFreeThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doubleFree).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbort); - connect(action, &QAction::triggered, qApp, []() { crash::doAbort(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbortThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doAbort).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbort); + connect(action, &QAction::triggered, qApp, []() { crash::doAbort(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbortThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doAbort).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereference); - connect(action, &QAction::triggered, qApp, []() { crash::nullDeref(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereferenceThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::nullDeref).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereference); + connect(action, &QAction::triggered, qApp, []() { crash::nullDeref(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereferenceThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::nullDeref).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccess); - connect(action, &QAction::triggered, qApp, []() { crash::outOfBoundsVectorCrash(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccessThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::outOfBoundsVectorCrash).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccess); + connect(action, &QAction::triggered, qApp, []() { crash::outOfBoundsVectorCrash(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccessThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::outOfBoundsVectorCrash).join(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFault); - connect(action, &QAction::triggered, qApp, []() { crash::newFault(); }); - action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFaultThreaded); - connect(action, &QAction::triggered, qApp, []() { std::thread(crash::newFault).join(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFault); + connect(action, &QAction::triggered, qApp, []() { crash::newFault(); }); + action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFaultThreaded); + connect(action, &QAction::triggered, qApp, []() { std::thread(crash::newFault).join(); }); - addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOnShutdown, 0, qApp, SLOT(crashOnShutdown())); + addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOnShutdown, 0, qApp, SLOT(crashOnShutdown())); + } + // Developer > Show Statistics addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats, 0, true); From f9c5d00efa8ad1dfdc6eb3ee6d15044486b8ceeb Mon Sep 17 00:00:00 2001 From: milad Date: Wed, 11 Sep 2019 12:10:47 -0700 Subject: [PATCH 15/20] remove source from variable name --- interface/src/Menu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7c260e16b9..193de2792d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -726,8 +726,8 @@ Menu::Menu() { // Developer > Crash >>> bool result = false; - const QString HIFI_SHOW_SOURCE_DEVELOPER_CRASH_MENU("HIFI_SHOW_SOURCE_DEVELOPER_CRASH_MENU"); - result = QProcessEnvironment::systemEnvironment().contains(HIFI_SHOW_SOURCE_DEVELOPER_CRASH_MENU); + const QString HIFI_SHOW_DEVELOPER_CRASH_MENU("HIFI_SHOW_DEVELOPER_CRASH_MENU"); + result = QProcessEnvironment::systemEnvironment().contains(HIFI_SHOW_DEVELOPER_CRASH_MENU); if (result) { MenuWrapper* crashMenu = developerMenu->addMenu("Crash"); From 3cf56210b239b15dce26e8e69a0a8fa3c3b478c5 Mon Sep 17 00:00:00 2001 From: milad Date: Wed, 11 Sep 2019 12:30:24 -0700 Subject: [PATCH 16/20] modified Audio.qml to handle desktop audio level meter visible --- interface/resources/qml/hifi/audio/Audio.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index d3bf6aca0a..dbfd46ded1 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -266,6 +266,7 @@ Rectangle { labelTextSize: 16; backgroundOnColor: "#E3E3E3"; checked: AudioScriptingInterface.warnWhenMuted; + visible: bar.currentIndex === 0 ? false : true; onClicked: { AudioScriptingInterface.warnWhenMuted = checked; checked = Qt.binding(function() { return AudioScriptingInterface.warnWhenMuted; }); // restore binding @@ -277,8 +278,8 @@ Rectangle { id: audioLevelSwitch height: root.switchHeight; switchWidth: root.switchWidth; - anchors.top: warnMutedSwitch.bottom - anchors.topMargin: 24 + anchors.top: bar.currentIndex === 0 ? parent.top : warnMutedSwitch.bottom + anchors.topMargin: bar.currentIndex === 0 ? 0 : 24 anchors.left: parent.left labelTextOn: qsTr("Audio Level Meter"); labelTextSize: 16; From 275350c2fa7f7ba1de0ab07e866f16eb72d905b1 Mon Sep 17 00:00:00 2001 From: milad Date: Wed, 11 Sep 2019 12:38:29 -0700 Subject: [PATCH 17/20] removed sound from the out --- .../simplifiedUI/simplifiedEmote/emojiApp/simplifiedEmoji.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/simplifiedUI/simplifiedEmote/emojiApp/simplifiedEmoji.js b/scripts/simplifiedUI/simplifiedEmote/emojiApp/simplifiedEmoji.js index 1b16843b09..4363f5d899 100644 --- a/scripts/simplifiedUI/simplifiedEmote/emojiApp/simplifiedEmoji.js +++ b/scripts/simplifiedUI/simplifiedEmote/emojiApp/simplifiedEmoji.js @@ -326,9 +326,7 @@ function playPopAnimation() { if (popType === "in") { currentPopScale = MIN_POP_SCALE; } else { - // Start with the pop sound on the out currentPopScale = finalInPopScale ? finalInPopScale : MAX_POP_SCALE; - playSound(emojiDestroySound, DEFAULT_VOLUME, MyAvatar.position, true); } } From d95a803324b687bb1800dd6d31e4c39c67190b36 Mon Sep 17 00:00:00 2001 From: MiladNazeri Date: Wed, 11 Sep 2019 12:44:59 -0700 Subject: [PATCH 18/20] Update interface/resources/qml/hifi/audio/Audio.qml Co-Authored-By: Zach Fox --- interface/resources/qml/hifi/audio/Audio.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index dbfd46ded1..d177094d92 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -266,7 +266,7 @@ Rectangle { labelTextSize: 16; backgroundOnColor: "#E3E3E3"; checked: AudioScriptingInterface.warnWhenMuted; - visible: bar.currentIndex === 0 ? false : true; + visible: bar.currentIndex !== 0; onClicked: { AudioScriptingInterface.warnWhenMuted = checked; checked = Qt.binding(function() { return AudioScriptingInterface.warnWhenMuted; }); // restore binding From a9da5b8f16a16e2162cc75cfe3b04563f9033827 Mon Sep 17 00:00:00 2001 From: MiladNazeri Date: Wed, 11 Sep 2019 12:45:18 -0700 Subject: [PATCH 19/20] Update interface/resources/qml/hifi/audio/Audio.qml Co-Authored-By: Zach Fox --- interface/resources/qml/hifi/audio/Audio.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index d177094d92..fccba12a8a 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -278,7 +278,7 @@ Rectangle { id: audioLevelSwitch height: root.switchHeight; switchWidth: root.switchWidth; - anchors.top: bar.currentIndex === 0 ? parent.top : warnMutedSwitch.bottom + anchors.top: warnMutedSwitch.visible ? warnMutedSwitch.bottom : parent.top anchors.topMargin: bar.currentIndex === 0 ? 0 : 24 anchors.left: parent.left labelTextOn: qsTr("Audio Level Meter"); From 4c340746c53060dc7b998c5b346372db24566092 Mon Sep 17 00:00:00 2001 From: milad Date: Wed, 11 Sep 2019 12:50:49 -0700 Subject: [PATCH 20/20] removed references to the emoji destroy sound --- .../resources/sounds/emojiPopSound2.wav | Bin 105984 -> 0 bytes .../emojiApp/simplifiedEmoji.js | 1 - 2 files changed, 1 deletion(-) delete mode 100644 scripts/simplifiedUI/simplifiedEmote/emojiApp/resources/sounds/emojiPopSound2.wav diff --git a/scripts/simplifiedUI/simplifiedEmote/emojiApp/resources/sounds/emojiPopSound2.wav b/scripts/simplifiedUI/simplifiedEmote/emojiApp/resources/sounds/emojiPopSound2.wav deleted file mode 100644 index 3d917997a721e2e758a168a298f1e57c5813aa45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105984 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