mirror of
https://github.com/overte-org/overte.git
synced 2025-04-12 10:42:10 +02:00
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
This commit is contained in:
parent
de53b9b11d
commit
e9e9607a3b
21 changed files with 302 additions and 62 deletions
|
@ -84,7 +84,7 @@ Agent::Agent(ReceivedMessage& message) :
|
||||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||||
|
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
DependencyManager::set<PluginManager>();
|
DependencyManager::set<PluginManager>()->instantiate();
|
||||||
|
|
||||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||||
|
|
||||||
|
@ -511,6 +511,7 @@ void Agent::executeScript() {
|
||||||
|
|
||||||
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
||||||
|
|
||||||
|
DependencyManager::get<ScriptEngines>()->runScriptInitializers(_scriptEngine);
|
||||||
_scriptEngine->run();
|
_scriptEngine->run();
|
||||||
|
|
||||||
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <HifiConfigVariantMap.h>
|
#include <HifiConfigVariantMap.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <ShutdownEventListener.h>
|
#include <ShutdownEventListener.h>
|
||||||
|
#include <shared/ScriptInitializerMixin.h>
|
||||||
|
|
||||||
#include "Assignment.h"
|
#include "Assignment.h"
|
||||||
#include "AssignmentClient.h"
|
#include "AssignmentClient.h"
|
||||||
|
@ -240,6 +241,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||||
QThread::currentThread()->setObjectName("main thread");
|
QThread::currentThread()->setObjectName("main thread");
|
||||||
|
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
|
DependencyManager::set<ScriptInitializers>();
|
||||||
|
|
||||||
if (numForks || minForks || maxForks) {
|
if (numForks || minForks || maxForks) {
|
||||||
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
|
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <SimpleEntitySimulation.h>
|
#include <SimpleEntitySimulation.h>
|
||||||
#include <ResourceCache.h>
|
#include <ResourceCache.h>
|
||||||
#include <ScriptCache.h>
|
#include <ScriptCache.h>
|
||||||
|
#include <plugins/PluginManager.h>
|
||||||
#include <EntityEditFilters.h>
|
#include <EntityEditFilters.h>
|
||||||
#include <NetworkingConstants.h>
|
#include <NetworkingConstants.h>
|
||||||
#include <hfm/ModelFormatRegistry.h>
|
#include <hfm/ModelFormatRegistry.h>
|
||||||
|
@ -42,6 +43,7 @@ EntityServer::EntityServer(ReceivedMessage& message) :
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
DependencyManager::set<ResourceCacheSharedItems>();
|
DependencyManager::set<ResourceCacheSharedItems>();
|
||||||
DependencyManager::set<ScriptCache>();
|
DependencyManager::set<ScriptCache>();
|
||||||
|
DependencyManager::set<PluginManager>()->instantiate();
|
||||||
|
|
||||||
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
|
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
|
||||||
DependencyManager::set<AssignmentDynamicFactory>();
|
DependencyManager::set<AssignmentDynamicFactory>();
|
||||||
|
|
|
@ -64,7 +64,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
||||||
DependencyManager::set<ResourceScriptingInterface>();
|
DependencyManager::set<ResourceScriptingInterface>();
|
||||||
|
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
DependencyManager::set<PluginManager>();
|
DependencyManager::set<PluginManager>()->instantiate();
|
||||||
|
|
||||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||||
|
|
||||||
|
@ -454,7 +454,7 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
|
||||||
_entityViewer.getTree()->update();
|
_entityViewer.getTree()->update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
scriptEngines->runScriptInitializers(newEngine);
|
||||||
newEngine->runInThread();
|
newEngine->runInThread();
|
||||||
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
|
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
|
||||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);
|
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);
|
||||||
|
|
|
@ -814,6 +814,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the plugin manager about our statically linked plugins
|
// Tell the plugin manager about our statically linked plugins
|
||||||
|
DependencyManager::set<ScriptInitializers>();
|
||||||
DependencyManager::set<PluginManager>();
|
DependencyManager::set<PluginManager>();
|
||||||
auto pluginManager = PluginManager::getInstance();
|
auto pluginManager = PluginManager::getInstance();
|
||||||
pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
|
pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
|
||||||
|
@ -863,7 +864,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
#endif
|
#endif
|
||||||
DependencyManager::set<StatTracker>();
|
DependencyManager::set<StatTracker>();
|
||||||
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT, defaultScriptsOverrideOption);
|
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT, defaultScriptsOverrideOption);
|
||||||
DependencyManager::set<ScriptInitializerMixin, NativeScriptInitializers>();
|
|
||||||
DependencyManager::set<Preferences>();
|
DependencyManager::set<Preferences>();
|
||||||
DependencyManager::set<recording::Deck>();
|
DependencyManager::set<recording::Deck>();
|
||||||
DependencyManager::set<recording::Recorder>();
|
DependencyManager::set<recording::Recorder>();
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include <PrioritySortUtil.h>
|
#include <PrioritySortUtil.h>
|
||||||
#include <Rig.h>
|
#include <Rig.h>
|
||||||
#include <SceneScriptingInterface.h>
|
#include <SceneScriptingInterface.h>
|
||||||
#include <ScriptEngine.h>
|
#include <ScriptEngines.h>
|
||||||
#include <EntitySimulation.h>
|
#include <EntitySimulation.h>
|
||||||
#include <ZoneRenderer.h>
|
#include <ZoneRenderer.h>
|
||||||
#include <PhysicalEntitySimulation.h>
|
#include <PhysicalEntitySimulation.h>
|
||||||
|
@ -146,7 +146,7 @@ int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
|
||||||
void EntityTreeRenderer::resetEntitiesScriptEngine() {
|
void EntityTreeRenderer::resetEntitiesScriptEngine() {
|
||||||
_entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
|
_entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
|
||||||
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
|
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
|
||||||
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
|
DependencyManager::get<ScriptEngines>()->runScriptInitializers(_entitiesScriptEngine);
|
||||||
_entitiesScriptEngine->runInThread();
|
_entitiesScriptEngine->runInThread();
|
||||||
auto entitiesScriptEngineProvider = qSharedPointerCast<EntitiesScriptEngineProvider>(_entitiesScriptEngine);
|
auto entitiesScriptEngineProvider = qSharedPointerCast<EntitiesScriptEngineProvider>(_entitiesScriptEngine);
|
||||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include <ResourceManager.h>
|
#include <ResourceManager.h>
|
||||||
|
#include <shared/ScriptInitializerMixin.h>
|
||||||
|
|
||||||
QList<EntityItemID> EntityEditFilters::getZonesByPosition(glm::vec3& position) {
|
QList<EntityItemID> EntityEditFilters::getZonesByPosition(glm::vec3& position) {
|
||||||
QList<EntityItemID> zones;
|
QList<EntityItemID> zones;
|
||||||
|
@ -258,7 +259,13 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) {
|
||||||
if (hasCorrectSyntax(program)) {
|
if (hasCorrectSyntax(program)) {
|
||||||
// create a QScriptEngine for this script
|
// create a QScriptEngine for this script
|
||||||
QScriptEngine* engine = new QScriptEngine();
|
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<ScriptInitializers>()->runScriptInitializers(engine);
|
||||||
|
engine->evaluate(scriptContents, urlString);
|
||||||
if (!hadUncaughtExceptions(*engine, urlString)) {
|
if (!hadUncaughtExceptions(*engine, urlString)) {
|
||||||
// put the engine in the engine map (so we don't leak them, etc...)
|
// put the engine in the engine map (so we don't leak them, etc...)
|
||||||
FilterData filterData;
|
FilterData filterData;
|
||||||
|
|
|
@ -154,7 +154,7 @@ const char* Assignment::typeToString(Assignment::Type type) {
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const Assignment &assignment) {
|
QDebug operator<<(QDebug debug, const Assignment &assignment) {
|
||||||
debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) <<
|
debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) <<
|
||||||
", Type: " << assignment.getType();
|
", Type: " << assignment.getTypeName() << " (" << assignment.getType() << ")";
|
||||||
|
|
||||||
if (!assignment.getPool().isEmpty()) {
|
if (!assignment.getPool().isEmpty()) {
|
||||||
debug << ", Pool: " << assignment.getPool();
|
debug << ", Pool: " << assignment.getPool();
|
||||||
|
|
|
@ -29,6 +29,9 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) :
|
||||||
_domainServerTimer(this),
|
_domainServerTimer(this),
|
||||||
_statsTimer(this)
|
_statsTimer(this)
|
||||||
{
|
{
|
||||||
|
// use <mixer-type> 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;
|
static const int STATS_TIMEOUT_MS = 1000;
|
||||||
_statsTimer.setInterval(STATS_TIMEOUT_MS); // 1s, Qt::CoarseTimer acceptable
|
_statsTimer.setInterval(STATS_TIMEOUT_MS); // 1s, Qt::CoarseTimer acceptable
|
||||||
connect(&_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket);
|
connect(&_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket);
|
||||||
|
|
|
@ -84,6 +84,11 @@ bool isDisabled(QJsonObject metaData) {
|
||||||
return false;
|
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& {
|
auto PluginManager::getLoadedPlugins() const -> const LoaderList& {
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
static LoaderList loadedPlugins;
|
static LoaderList loadedPlugins;
|
||||||
|
@ -139,7 +144,7 @@ bool isDisabled(QJsonObject metaData) {
|
||||||
qCDebug(plugins) << " " << qPrintable(loader->errorString());
|
qCDebug(plugins) << " " << qPrintable(loader->errorString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else qWarning() << "pluginPath does not exit..." << pluginDir;
|
||||||
});
|
});
|
||||||
return loadedPlugins;
|
return loadedPlugins;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
void setContainer(PluginContainer* container) { _container = container; }
|
void setContainer(PluginContainer* container) { _container = container; }
|
||||||
|
|
||||||
|
int instantiate();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
// Application that have statically linked plugins can expose them to the plugin manager with these function
|
// Application that have statically linked plugins can expose them to the plugin manager with these function
|
||||||
|
|
|
@ -190,6 +190,7 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const
|
||||||
case Context::ENTITY_SERVER_SCRIPT:
|
case Context::ENTITY_SERVER_SCRIPT:
|
||||||
_type = Type::ENTITY_SERVER;
|
_type = Type::ENTITY_SERVER;
|
||||||
break;
|
break;
|
||||||
|
case Context::EDIT_FILTER_SCRIPT:
|
||||||
case Context::AGENT_SCRIPT:
|
case Context::AGENT_SCRIPT:
|
||||||
_type = Type::AGENT;
|
_type = Type::AGENT;
|
||||||
break;
|
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 {
|
QString ScriptEngine::getContext() const {
|
||||||
switch (_context) {
|
switch (_context) {
|
||||||
case CLIENT_SCRIPT:
|
case CLIENT_SCRIPT:
|
||||||
|
|
|
@ -122,13 +122,16 @@ public:
|
||||||
class ScriptEngine : public BaseScriptEngine, public EntitiesScriptEngineProvider {
|
class ScriptEngine : public BaseScriptEngine, public EntitiesScriptEngineProvider {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString context READ getContext)
|
Q_PROPERTY(QString context READ getContext)
|
||||||
|
Q_PROPERTY(QString type READ getTypeAsString)
|
||||||
|
Q_PROPERTY(QString fileName MEMBER _fileNameString CONSTANT)
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Context {
|
enum Context {
|
||||||
CLIENT_SCRIPT,
|
CLIENT_SCRIPT,
|
||||||
ENTITY_CLIENT_SCRIPT,
|
ENTITY_CLIENT_SCRIPT,
|
||||||
ENTITY_SERVER_SCRIPT,
|
ENTITY_SERVER_SCRIPT,
|
||||||
AGENT_SCRIPT
|
AGENT_SCRIPT,
|
||||||
|
EDIT_FILTER_SCRIPT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -138,6 +141,7 @@ public:
|
||||||
AGENT,
|
AGENT,
|
||||||
AVATAR
|
AVATAR
|
||||||
};
|
};
|
||||||
|
Q_ENUM(Type)
|
||||||
|
|
||||||
static int processLevelMaxRetries;
|
static int processLevelMaxRetries;
|
||||||
ScriptEngine(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine"));
|
ScriptEngine(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine"));
|
||||||
|
@ -274,6 +278,7 @@ public:
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE QString getContext() const;
|
Q_INVOKABLE QString getContext() const;
|
||||||
|
Q_INVOKABLE QString getTypeAsString() const;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Checks whether the script is running as an Interface or avatar script.
|
* Checks whether the script is running as an Interface or avatar script.
|
||||||
|
|
|
@ -136,24 +136,6 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) {
|
||||||
|
|
||||||
QObject* scriptsModel();
|
QObject* scriptsModel();
|
||||||
|
|
||||||
bool NativeScriptInitializers::registerNativeScriptInitializer(NativeScriptInitializer initializer) {
|
|
||||||
return registerScriptInitializer([initializer](ScriptEnginePointer engine) {
|
|
||||||
initializer(qobject_cast<QScriptEngine*>(engine.data()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NativeScriptInitializers::registerScriptInitializer(ScriptInitializer initializer) {
|
|
||||||
if (auto scriptEngines = DependencyManager::get<ScriptEngines>().data()) {
|
|
||||||
scriptEngines->registerScriptInitializer(initializer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) {
|
|
||||||
_scriptInitializers.push_back(initializer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptEngines::addScriptEngine(ScriptEnginePointer engine) {
|
void ScriptEngines::addScriptEngine(ScriptEnginePointer engine) {
|
||||||
if (!_isStopped) {
|
if (!_isStopped) {
|
||||||
QMutexLocker locker(&_allScriptsMutex);
|
QMutexLocker locker(&_allScriptsMutex);
|
||||||
|
@ -559,12 +541,10 @@ void ScriptEngines::quitWhenFinished() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) {
|
int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) {
|
||||||
int ii=0;
|
auto nativeCount = DependencyManager::get<ScriptInitializers>()->runScriptInitializers(scriptEngine.data());
|
||||||
for (auto initializer : _scriptInitializers) {
|
return nativeCount + std::count_if(_scriptInitializers.begin(), _scriptInitializers.end(),
|
||||||
ii++;
|
[scriptEngine](auto initializer){ initializer(scriptEngine); return true; }
|
||||||
initializer(scriptEngine);
|
);
|
||||||
}
|
|
||||||
return ii;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) {
|
void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) {
|
||||||
|
|
|
@ -40,13 +40,7 @@ class ScriptEngine;
|
||||||
* @property {ScriptsModelFilter} scriptsModelFilter
|
* @property {ScriptsModelFilter} scriptsModelFilter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class NativeScriptInitializers : public ScriptInitializerMixin {
|
class ScriptEngines : public QObject, public Dependency, public ScriptInitializerMixin<ScriptEnginePointer> {
|
||||||
public:
|
|
||||||
bool registerNativeScriptInitializer(NativeScriptInitializer initializer) override;
|
|
||||||
bool registerScriptInitializer(ScriptInitializer initializer) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ScriptEngines : public QObject, public Dependency {
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(ScriptsModel* scriptsModel READ scriptsModel CONSTANT)
|
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)
|
Q_PROPERTY(QString debugScriptUrl READ getDebugScriptUrl WRITE setDebugScriptUrl)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using ScriptInitializer = ScriptInitializerMixin::ScriptInitializer;
|
|
||||||
|
|
||||||
ScriptEngines(ScriptEngine::Context context, const QUrl& defaultScriptsOverride = QUrl());
|
ScriptEngines(ScriptEngine::Context context, const QUrl& defaultScriptsOverride = QUrl());
|
||||||
void registerScriptInitializer(ScriptInitializer initializer);
|
int runScriptInitializers(ScriptEnginePointer engine) override;
|
||||||
int runScriptInitializers(ScriptEnginePointer engine);
|
|
||||||
void loadScripts();
|
void loadScripts();
|
||||||
void saveScripts();
|
void saveScripts();
|
||||||
|
|
||||||
|
@ -277,7 +269,6 @@ protected:
|
||||||
QHash<QUrl, ScriptEnginePointer> _scriptEnginesHash;
|
QHash<QUrl, ScriptEnginePointer> _scriptEnginesHash;
|
||||||
QSet<ScriptEnginePointer> _allKnownScriptEngines;
|
QSet<ScriptEnginePointer> _allKnownScriptEngines;
|
||||||
QMutex _allScriptsMutex;
|
QMutex _allScriptsMutex;
|
||||||
std::list<ScriptInitializer> _scriptInitializers;
|
|
||||||
ScriptsModel _scriptsModel;
|
ScriptsModel _scriptsModel;
|
||||||
ScriptsModelFilter _scriptsModelFilter;
|
ScriptsModelFilter _scriptsModelFilter;
|
||||||
std::atomic<bool> _isStopped { false };
|
std::atomic<bool> _isStopped { false };
|
||||||
|
|
|
@ -9,30 +9,38 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include "../DependencyManager.h"
|
#include "../DependencyManager.h"
|
||||||
|
|
||||||
class QScriptEngine;
|
class QScriptEngine;
|
||||||
class ScriptEngine;
|
class ScriptEngine;
|
||||||
|
|
||||||
class ScriptInitializerMixin : public QObject, public Dependency {
|
template <typename T> class ScriptInitializerMixin {
|
||||||
Q_OBJECT
|
public:
|
||||||
|
using ScriptInitializer = std::function<void(T)>;
|
||||||
|
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::mutex>;
|
||||||
|
std::list<ScriptInitializer> _scriptInitializers;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScriptInitializers : public ScriptInitializerMixin<QScriptEngine*>, public Dependency {
|
||||||
public:
|
public:
|
||||||
// Lightweight `QScriptEngine*` initializer (only depends on built-in Qt components)
|
// Lightweight `QScriptEngine*` initializer (only depends on built-in Qt components)
|
||||||
// example registration:
|
// example registration:
|
||||||
// eg: [&](QScriptEngine* engine) -> bool {
|
// eg: [&](QScriptEngine* engine) {
|
||||||
// engine->globalObject().setProperties("API", engine->newQObject(...instance...))
|
// engine->globalObject().setProperties("API", engine->newQObject(...instance...))
|
||||||
// return true;
|
// };
|
||||||
// }
|
|
||||||
using NativeScriptInitializer = std::function<void(QScriptEngine*)>;
|
|
||||||
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<ScriptEngine>;
|
|
||||||
using ScriptInitializer = std::function<void(ScriptEnginePointer)>;
|
|
||||||
virtual bool registerScriptInitializer(ScriptInitializer initializer) { return false; };
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,3 +43,7 @@ set(DIR "pcmCodec")
|
||||||
add_subdirectory(${DIR})
|
add_subdirectory(${DIR})
|
||||||
set(DIR "hifiCodec")
|
set(DIR "hifiCodec")
|
||||||
add_subdirectory(${DIR})
|
add_subdirectory(${DIR})
|
||||||
|
|
||||||
|
# example plugins
|
||||||
|
set(DIR "KasenAPIExample")
|
||||||
|
add_subdirectory(${DIR})
|
||||||
|
|
7
plugins/KasenAPIExample/CMakeLists.txt
Normal file
7
plugins/KasenAPIExample/CMakeLists.txt
Normal file
|
@ -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()
|
58
plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h
Normal file
58
plugins/KasenAPIExample/src/DeprecatedScriptPlugin.h
Normal file
|
@ -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 <QtScript/QScriptEngine>
|
||||||
|
|
||||||
|
#include <QtCore/QLoggingCategory>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <shared/ScriptInitializerMixin.h>
|
||||||
|
|
||||||
|
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<ScriptInitializers>()) {
|
||||||
|
qCWarning(logger) << "COULD NOT INITIALIZE (ScriptInitializers unavailable)" << qApp << this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qCWarning(logger) << "registering w/ScriptInitializerMixin..." << DependencyManager::get<ScriptInitializers>().data();
|
||||||
|
DependencyManager::get<ScriptInitializers>()->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
|
139
plugins/KasenAPIExample/src/KasenAPIExample.cpp
Normal file
139
plugins/KasenAPIExample/src/KasenAPIExample.cpp
Normal file
|
@ -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 <QCoreApplication>
|
||||||
|
#include <QtCore/QJsonObject>
|
||||||
|
#include <QtCore/QLoggingCategory>
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
#include <QtCore/QTimer>
|
||||||
|
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
#include <AvatarHashMap.h>
|
||||||
|
|
||||||
|
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 <caption>Measure current setTimeout accuracy.</caption>
|
||||||
|
* 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 <caption>Get blendshape names</caption>
|
||||||
|
* print(JSON.stringify(KasenAPIExample.getBlendshapeNames(MyAvatar.sessionUUID)));
|
||||||
|
*/
|
||||||
|
QStringList getBlendshapeNames(const QUuid& avatarID) const {
|
||||||
|
QVector<QString> 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 <caption>Get active blendshape map</caption>
|
||||||
|
* 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<float>& 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<QString,int> getBlendshapeMap() const {
|
||||||
|
return _blendshapeLookupMap;
|
||||||
|
}
|
||||||
|
struct States { QVector<float> base, summed, transient; };
|
||||||
|
States getBlendshapeStates() const {
|
||||||
|
return {
|
||||||
|
_blendshapeCoefficients,
|
||||||
|
_summedBlendshapeCoefficients,
|
||||||
|
_transientBlendshapeCoefficients
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static const _HeadHelper* getAvatarHead(const QUuid& avatarID) {
|
||||||
|
auto avatars = DependencyManager::get<AvatarHashMap>();
|
||||||
|
auto avatar = avatars ? avatars->getAvatarBySessionID(avatarID) : nullptr;
|
||||||
|
auto head = avatar ? avatar->getHeadData() : nullptr;
|
||||||
|
return reinterpret_cast<const _HeadHelper*>(head);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const QLoggingCategory& deprecated::logger{ custom_api_example::logger };
|
||||||
|
|
||||||
|
#include "KasenAPIExample.moc"
|
21
plugins/KasenAPIExample/src/plugin.json
Normal file
21
plugins/KasenAPIExample/src/plugin.json
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue