Added script types and better script reload

This commit is contained in:
luiscuenca 2018-04-30 12:04:35 -07:00
parent 12f578c93c
commit 2de982a5a2
12 changed files with 81 additions and 33 deletions

View file

@ -1231,6 +1231,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, [this] {
getEntities()->reloadEntityScripts();
loadAvatarScripts(getMyAvatar()->getSkeletonModel()->getFBXGeometry().scripts);
}, Qt::QueuedConnection);
connect(scriptEngines, &ScriptEngines::scriptLoadError,
@ -2285,10 +2286,6 @@ void Application::onAboutToQuit() {
// Hide Running Scripts dialog so that it gets destroyed in an orderly manner; prevents warnings at shutdown.
DependencyManager::get<OffscreenUi>()->hide("RunningScripts");
if (auto avatar = getMyAvatar()) {
auto urls = avatar->getScriptsToUnload();
unloadAvatarScripts(urls);
}
_aboutToQuit = true;
@ -4737,18 +4734,24 @@ void Application::loadAvatarScripts(const QVector<QString>& urls) {
for (auto url : urls) {
int index = runningScripts.indexOf(url);
if (index < 0) {
scriptEngines->loadScript(url);
getMyAvatar()->addScriptToUnload(url);
auto scriptEnginePointer = scriptEngines->loadScript(url, false);
if (scriptEnginePointer) {
scriptEnginePointer->setType(ScriptEngine::Type::AVATAR);
}
}
}
}
}
void Application::unloadAvatarScripts(const QVector<QString>& urls) {
if (urls.size() > 0) {
auto scriptEngines = DependencyManager::get<ScriptEngines>();
void Application::unloadAvatarScripts() {
auto scriptEngines = DependencyManager::get<ScriptEngines>();
auto urls = scriptEngines->getRunningScripts();
if (urls.size() > 0) {
for (auto url : urls) {
scriptEngines->stopScript(url, false);
auto scriptEngine = scriptEngines->getScriptEngine(url);
if (scriptEngine->getType() == ScriptEngine::Type::AVATAR) {
scriptEngines->stopScript(url, false);
}
}
}
}

View file

@ -291,7 +291,7 @@ public:
void replaceDomainContent(const QString& url);
void loadAvatarScripts(const QVector<QString>& urls);
void unloadAvatarScripts(const QVector<QString>& urls);
void unloadAvatarScripts();
signals:
void svoImportRequested(const QString& url);

View file

@ -177,6 +177,7 @@ bool ModelPackager::zipModel() {
_scriptDir = _modelFile.path() + "/" + scriptField;
QDir wdir = QDir(_scriptDir);
_mapping.remove(SCRIPT_FIELD);
wdir.setSorting(QDir::Name | QDir::Reversed);
auto list = wdir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries);
for (auto script : list) {
auto sc = tempDir.relativeFilePath(scriptDir.path()) + "/" + QUrl(script).fileName();

View file

@ -123,6 +123,7 @@ MyAvatar::MyAvatar(QThread* thread) :
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
connect(_skeletonModel.get(), &Model::setURLFinished, this, [this](bool success) {
if (success) {
qApp->unloadAvatarScripts();
auto geometry = getSkeletonModel()->getFBXGeometry();
qApp->loadAvatarScripts(geometry.scripts);
}
@ -1469,7 +1470,6 @@ void MyAvatar::clearJointsData() {
}
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
qApp->unloadAvatarScripts(_scriptsToUnload);
_skeletonModelChangeCount++;
int skeletonModelChangeCount = _skeletonModelChangeCount;
Avatar::setSkeletonModelURL(skeletonModelURL);
@ -2838,10 +2838,6 @@ float MyAvatar::getWalkSpeed() const {
return _walkSpeed.get() * _walkSpeedScalar;
}
void MyAvatar::addScriptToUnload(const QString& url) {
_scriptsToUnload.push_back(url);
}
void MyAvatar::setSprintMode(bool sprint) {
_walkSpeedScalar = sprint ? AVATAR_SPRINT_SPEED_SCALAR : AVATAR_WALK_SPEED_SCALAR;
}

View file

@ -594,9 +594,6 @@ public:
void setWalkSpeed(float value);
float getWalkSpeed() const;
void addScriptToUnload(const QString& url);
const QVector<QString>& getScriptsToUnload() const { return _scriptsToUnload; };
public slots:
void increaseSize();
void decreaseSize();
@ -907,8 +904,6 @@ private:
// max unscaled forward movement speed
ThreadSafeValueCache<float> _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR };
QVector<QString> _scriptsToUnload;
};
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);

View file

@ -187,6 +187,28 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) {
return ENTITY_MODEL;
}
QVector<QString> FSTReader::getScripts(const QUrl& url, const QVariantHash& mapping) {
auto fstMapping = mapping.isEmpty() ? downloadMapping(url.toString()) : mapping;
QVector<QString> scriptPaths;
if (!fstMapping.value(SCRIPT_FIELD).isNull()) {
auto scripts = fstMapping.values(SCRIPT_FIELD).toVector();
if (scripts.size() > 0) {
for (auto &script : scripts) {
QString scriptPath = script.toString();
if (QUrl(scriptPath).isRelative()) {
if (scriptPath.at(0) == '/') {
scriptPath = scriptPath.right(scriptPath.length() - 1);
}
scriptPath = url.resolved(QUrl(scriptPath)).toString();
}
scriptPaths.push_back(scriptPath);
}
}
}
return scriptPaths;
}
QVariantHash FSTReader::downloadMapping(const QString& url) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest = QNetworkRequest(url);

View file

@ -50,6 +50,8 @@ public:
/// Predicts the type of model by examining the mapping
static ModelType predictModelType(const QVariantHash& mapping);
static QVector<QString> getScripts(const QUrl& fstUrl, const QVariantHash& mapping = QVariantHash());
static QString getNameFromType(ModelType modelType);
static FSTReader::ModelType getTypeFromName(const QString& name);
static QVariantHash downloadMapping(const QString& url);

View file

@ -83,6 +83,14 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
_textureBaseUrl = url.resolved(QUrl("."));
}
auto scripts = FSTReader::getScripts(_url, mapping);
if (scripts.size() > 0) {
mapping.remove(SCRIPT_FIELD);
for (auto &scriptPath : scripts) {
mapping.insertMulti(SCRIPT_FIELD, scriptPath);
}
}
auto animGraphVariant = mapping.value("animGraphUrl");
if (animGraphVariant.isValid()) {
QUrl fstUrl(animGraphVariant.toString());
@ -210,19 +218,12 @@ void GeometryReader::run() {
throw QString("unsupported format");
}
// Store fst scripts on geometry
// Add scripts to fbxgeometry
if (!_mapping.value(SCRIPT_FIELD).isNull()) {
QVariantList scripts = _mapping.values(SCRIPT_FIELD);
if (scripts.size() > 0) {
for (auto &script : scripts) {
QString scriptUrl = script.toString();
if (QUrl(scriptUrl).isRelative()) {
if (scriptUrl.at(0) == '/') {
scriptUrl = scriptUrl.right(scriptUrl.length() - 1);
}
scriptUrl = _url.resolved(QUrl(scriptUrl)).toString();
}
fbxGeometry->scripts.push_back(scriptUrl);
fbxGeometry->scripts.push_back(script.toString());
}
}
}

View file

@ -180,6 +180,20 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const
// don't delete `ScriptEngines` until all `ScriptEngine`s are gone
_scriptEngines(DependencyManager::get<ScriptEngines>())
{
switch (_context) {
case Context::CLIENT_SCRIPT:
_type = Type::CLIENT;
break;
case Context::ENTITY_CLIENT_SCRIPT:
_type = Type::ENTITY_CLIENT;
break;
case Context::ENTITY_SERVER_SCRIPT:
_type = Type::ENTITY_SERVER;
break;
case Context::AGENT_SCRIPT:
_type = Type::AGENT;
}
connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {
if (hasUncaughtException()) {
// the engine's uncaughtException() seems to produce much better stack traces here

View file

@ -99,6 +99,14 @@ public:
AGENT_SCRIPT
};
enum Type {
CLIENT,
ENTITY_CLIENT,
ENTITY_SERVER,
AGENT,
AVATAR
};
static int processLevelMaxRetries;
ScriptEngine(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine"));
~ScriptEngine();
@ -209,6 +217,9 @@ public:
Q_INVOKABLE QUuid generateUUID() { return QUuid::createUuid(); }
void setType(Type type) { _type = type; };
Type getType() { return _type; };
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
bool isRunning() const { return _isRunning; } // used by ScriptWidget
@ -293,6 +304,7 @@ protected:
void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args);
Context _context;
Type _type;
QString _scriptContents;
QString _parentURL;
std::atomic<bool> _isFinished { false };

View file

@ -427,11 +427,13 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) {
if (_scriptEnginesHash.contains(scriptURL)) {
ScriptEnginePointer scriptEngine = _scriptEnginesHash[scriptURL];
if (restart) {
bool isUserLoaded = scriptEngine->isUserLoaded();
ScriptEngine::Type type = scriptEngine->getType();
auto scriptCache = DependencyManager::get<ScriptCache>();
scriptCache->deleteScript(scriptURL);
connect(scriptEngine.data(), &ScriptEngine::finished,
this, [this](QString scriptName, ScriptEnginePointer engine) {
reloadScript(scriptName);
this, [this, isUserLoaded, type](QString scriptName, ScriptEnginePointer engine) {
reloadScript(scriptName, isUserLoaded)->setType(type);
});
}
scriptEngine->stop();

View file

@ -110,7 +110,7 @@ protected slots:
protected:
friend class ScriptEngine;
void reloadScript(const QString& scriptName) { loadScript(scriptName, true, false, false, true); }
ScriptEnginePointer reloadScript(const QString& scriptName, bool isUserLoaded = true) { return loadScript(scriptName, isUserLoaded, false, false, true); }
void removeScriptEngine(ScriptEnginePointer);
void onScriptEngineLoaded(const QString& scriptFilename);
void onScriptEngineError(const QString& scriptFilename);