diff --git a/include/config.h b/include/config.h index f1b1d91b..19c64850 100644 --- a/include/config.h +++ b/include/config.h @@ -113,6 +113,7 @@ public: this->baseGameVersion = BaseGameVersion::pokeemerald; this->useEncounterJson = true; this->useCustomBorderSize = false; + this->customScripts.clear(); } void setBaseGameVersion(BaseGameVersion baseGameVersion); BaseGameVersion getBaseGameVersion(); @@ -121,8 +122,11 @@ public: void setUsePoryScript(bool usePoryScript); bool getUsePoryScript(); void setProjectDir(QString projectDir); + QString getProjectDir(); void setUseCustomBorderSize(bool enable); bool getUseCustomBorderSize(); + void setCustomScripts(QList scripts); + QList getCustomScripts(); protected: virtual QString getConfigFilepath() override; virtual void parseConfigKeyValue(QString key, QString value) override; @@ -134,6 +138,7 @@ private: bool useEncounterJson; bool usePoryScript; bool useCustomBorderSize; + QList customScripts; }; extern ProjectConfig projectConfig; diff --git a/include/mainwindow.h b/include/mainwindow.h index 764a0a9e..09cc440c 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -253,6 +253,8 @@ private: DraggablePixmapItem *selectedBG; DraggablePixmapItem *selectedHealspot; + QList registeredActions; + bool isProgrammaticEventTabChange; bool projectHasUnsavedChanges; diff --git a/include/scripting.h b/include/scripting.h index e9fc9916..99daac89 100644 --- a/include/scripting.h +++ b/include/scripting.h @@ -9,6 +9,7 @@ enum CallbackType { OnProjectOpened, + OnProjectClosed, OnBlockChanged, OnMapOpened, }; @@ -25,6 +26,7 @@ public: static int numRegisteredActions(); static void invokeAction(QString actionName); static void cb_ProjectOpened(QString projectPath); + static void cb_ProjectClosed(QString projectPath); static void cb_MetatileChanged(int x, int y, Block prevBlock, Block newBlock); static void cb_MapOpened(QString mapName); diff --git a/src/config.cpp b/src/config.cpp index 80fcaa83..0c102cf6 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -36,7 +36,7 @@ void KeyValueConfigBase::load() { QTextStream in(&file); in.setCodec("UTF-8"); QList configLines; - QRegularExpression re("^(?.+)=(?.+)$"); + QRegularExpression re("^(?.+)=(?.*)$"); while (!in.atEnd()) { QString line = in.readLine().trimmed(); int commentIndex = line.indexOf("#"); @@ -380,6 +380,15 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { if (!ok) { logWarn(QString("Invalid config value for use_custom_border_size: '%1'. Must be 0 or 1.").arg(value)); } + } else if (key == "custom_scripts") { + this->customScripts.clear(); + QList paths = value.split(","); + paths.removeDuplicates(); + for (QString script : paths) { + if (!script.isEmpty()) { + this->customScripts.append(script); + } + } } else { logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key)); } @@ -391,6 +400,7 @@ QMap ProjectConfig::getKeyValueMap() { map.insert("use_encounter_json", QString::number(this->useEncounterJson)); map.insert("use_poryscript", QString::number(this->usePoryScript)); map.insert("use_custom_border_size", QString::number(this->useCustomBorderSize)); + map.insert("custom_scripts", this->customScripts.join(",")); return map; } @@ -423,12 +433,17 @@ void ProjectConfig::onNewConfigFileCreated() { this->useCustomBorderSize = this->baseGameVersion == BaseGameVersion::pokefirered; this->useEncounterJson = true; this->usePoryScript = false; + this->customScripts.clear(); } void ProjectConfig::setProjectDir(QString projectDir) { this->projectDir = projectDir; } +QString ProjectConfig::getProjectDir() { + return this->projectDir; +} + void ProjectConfig::setBaseGameVersion(BaseGameVersion baseGameVersion) { this->baseGameVersion = baseGameVersion; this->save(); @@ -464,3 +479,12 @@ void ProjectConfig::setUseCustomBorderSize(bool enable) { bool ProjectConfig::getUseCustomBorderSize() { return this->useCustomBorderSize; } + +void ProjectConfig::setCustomScripts(QList scripts) { + this->customScripts = scripts; + this->save(); +} + +QList ProjectConfig::getCustomScripts() { + return this->customScripts; +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f4328f1a..be796043 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -46,7 +46,6 @@ MainWindow::MainWindow(QWidget *parent) : QCoreApplication::setApplicationName("porymap"); QApplication::setApplicationDisplayName("porymap"); QApplication::setWindowIcon(QIcon(":/icons/porymap-icon-2.ico")); - Scripting::init(this); ui->setupUi(this); this->initWindow(); @@ -349,6 +348,10 @@ bool MainWindow::openProject(QString dir) { } if (success) { + for (auto action : this->registeredActions) { + this->ui->menuTools->removeAction(action); + } + Scripting::init(this); Scripting::cb_ProjectOpened(dir); } @@ -395,6 +398,7 @@ void MainWindow::on_action_Open_Project_triggered() } QString dir = getExistingDirectory(recent); if (!dir.isEmpty()) { + Scripting::cb_ProjectClosed(this->editor->project->root); porymapConfig.setRecentProject(dir); if (!openProject(dir)) { this->initWindow(); diff --git a/src/mainwindow_scriptapi.cpp b/src/mainwindow_scriptapi.cpp index f321595e..6dc84151 100644 --- a/src/mainwindow_scriptapi.cpp +++ b/src/mainwindow_scriptapi.cpp @@ -434,7 +434,8 @@ void MainWindow::registerAction(QString functionName, QString actionName, QStrin Scripting::registerAction(functionName, actionName); if (Scripting::numRegisteredActions() == 1) { - this->ui->menuTools->addSection("Custom Actions"); + QAction *section = this->ui->menuTools->addSection("Custom Actions"); + this->registeredActions.append(section); } QAction *action = this->ui->menuTools->addAction(actionName, [actionName](){ Scripting::invokeAction(actionName); @@ -442,6 +443,7 @@ void MainWindow::registerAction(QString functionName, QString actionName, QStrin if (!shortcut.isEmpty()) { action->setShortcut(QKeySequence(shortcut)); } + this->registeredActions.append(action); } void MainWindow::setTimeout(QJSValue callback, int milliseconds) { diff --git a/src/scripting.cpp b/src/scripting.cpp index ecd34d51..2df636f8 100644 --- a/src/scripting.cpp +++ b/src/scripting.cpp @@ -2,14 +2,19 @@ #include "log.h" QMap callbackFunctions = { - {OnProjectOpened, "on_project_opened"}, - {OnBlockChanged, "on_block_changed"}, - {OnMapOpened, "on_map_opened"}, + {OnProjectOpened, "onProjectOpened"}, + {OnProjectClosed, "onProjectClosed"}, + {OnBlockChanged, "onBlockChanged"}, + {OnMapOpened, "onMapOpened"}, }; Scripting *instance = nullptr; void Scripting::init(MainWindow *mainWindow) { + if (instance) { + instance->engine->setInterrupted(true); + delete instance; + } instance = new Scripting(mainWindow); } @@ -17,7 +22,9 @@ Scripting::Scripting(MainWindow *mainWindow) { this->engine = new QJSEngine(mainWindow); this->engine->installExtensions(QJSEngine::ConsoleExtension); this->engine->globalObject().setProperty("map", this->engine->newQObject(mainWindow)); - this->filepaths.append("D:\\devkitProOld\\msys\\home\\huder\\pretmap\\test_script.js"); + for (QString script : projectConfig.getCustomScripts()) { + this->filepaths.append(script); + } this->loadModules(this->filepaths); } @@ -25,16 +32,21 @@ void Scripting::loadModules(QStringList moduleFiles) { for (QString filepath : moduleFiles) { QJSValue module = this->engine->importModule(filepath); if (module.isError()) { - logError(QString("Failed to load custom script file '%1'\nName: %2\nMessage: %3\nFile: %4\nLine Number: %5\nStack: %6") - .arg(filepath) - .arg(module.property("name").toString()) - .arg(module.property("message").toString()) - .arg(module.property("fileName").toString()) - .arg(module.property("lineNumber").toString()) - .arg(module.property("stack").toString())); - continue; + QString relativePath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath); + module = this->engine->importModule(relativePath); + if (module.isError()) { + logError(QString("Failed to load custom script file '%1'\nName: %2\nMessage: %3\nFile: %4\nLine Number: %5\nStack: %6") + .arg(filepath) + .arg(module.property("name").toString()) + .arg(module.property("message").toString()) + .arg(module.property("fileName").toString()) + .arg(module.property("lineNumber").toString()) + .arg(module.property("stack").toString())); + continue; + } } + logInfo(QString("Successfully loaded custom script file '%1'").arg(filepath)); this->modules.append(module); } } @@ -93,6 +105,15 @@ void Scripting::cb_ProjectOpened(QString projectPath) { instance->invokeCallback(OnProjectOpened, args); } +void Scripting::cb_ProjectClosed(QString projectPath) { + if (!instance) return; + + QJSValueList args { + projectPath, + }; + instance->invokeCallback(OnProjectClosed, args); +} + void Scripting::cb_MetatileChanged(int x, int y, Block prevBlock, Block newBlock) { if (!instance) return;